@nextclaw/ui 0.15.25 → 0.15.27
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 +34 -0
- package/dist/assets/{abnfDiagram-VRR7QNED-DvTjgVMf.js → abnfDiagram-VRR7QNED-BcFJp_1X.js} +1 -1
- package/dist/assets/{aiden0z-pptx-renderer.es-C1nfBAXR.js → aiden0z-pptx-renderer.es-Dp2ezlQn.js} +1 -1
- package/dist/assets/{api-FK7tikI1.js → api-a_GaOFc7.js} +6 -6
- package/dist/assets/appearance-settings-page-DlGXLgff.js +1 -0
- package/dist/assets/{arc-BvhODBXv.js → arc-CkgyPMyW.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-DO2x53FK.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-BKO9RgNS.js → architectureDiagram-ZJ3FMSHR-CMd4cIjI.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-DHpDXy7D.js → blockDiagram-677ZJIJ3-Bz3tbhet.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-BG_iQnDr.js → c4Diagram-LMCZKHZV-D9hFNAGv.js} +1 -1
- package/dist/assets/channel-nBvMaVyP.js +1 -0
- package/dist/assets/{channels-list-page-CocdcIko.js → channels-list-page-BEEk4Uc9.js} +2 -2
- package/dist/assets/chat-page-DUQXXqQm.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-CJgqFDS4.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-DR9M0LLx.js → chunk-32BRIVSS-7NrjEITq.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-698iC3BB.js → chunk-52WLFC77-viIcqj9q.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-DikTj9Ey.js → chunk-5FCAYU7R-Vsu4J-VM.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-ko0o7_q0.js → chunk-5HE753X5-C-w6CQZK.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-CEHufhgo.js → chunk-5JV3BV7I-CuKgJQ4W.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-CGgno1cu.js → chunk-5TONJI2A-CYeiWZKb.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DkiB4cUQ.js → chunk-5VM5RSS4-DRCbfwIn.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-DzptcytQ.js → chunk-7BUUIJ7U-BvydOcm3.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-DMRSQJvT.js → chunk-BIQX33UG-RlppOXKo.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-Bw1BwwuY.js → chunk-C7G6YPKG-DAizzYwr.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-C0z6eHBk.js → chunk-CQNSW5MT-5eChJHca.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-ByPyAouO.js → chunk-CYSBUYHQ-YHPr53fv.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-CJlAXWZg.js → chunk-EMLP6XTP-CK4D7Hz5.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-Dqq4zKJu.js → chunk-EX3LRPZG-BmlDFIRW.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-B0SNoCmi.js → chunk-FWX5IMBZ-D0ksHZZ9.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-DG_GJih_.js → chunk-HOUHSVGY-DPkq8FCm.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-Drxk_6bE.js → chunk-ICXQ74PX-FAatv5fC.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-DdLFPpnd.js → chunk-JG7HCLWE-DLkIi4F7.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-B8M4G76F.js → chunk-JWPE2WC7-DawOjNE3.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-XP6FJHY_.js → chunk-MOJQB5TN-Di52TorW.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-C_6x18Qw.js → chunk-MOZMSUNE-PfyK9w1-.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-N25BzCmG.js → chunk-OGEWGWER-C3jdH3Ty.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-ASDEm7y0.js → chunk-OSBZ3O6U-CecHo-f0.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-CTlvAcn7.js → chunk-PUDLZKDR-f3IJh3sN.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-Da9BWfB6.js → chunk-Q4XR5HBZ-DQFeUPxZ.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-Bi6RpTJO.js → chunk-QBLGF6JB-BhUeG0y2.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-DkMsSPvK.js → chunk-R7FJI6CG-C3XpZ-2u.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-DZp0eU-j.js → chunk-RYQCIY6F-CAqa5klQ.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-vfinDSrj.js → chunk-U6XO7XAA-D_WXezeD.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-C9Nksccs.js → chunk-V7JOEXUC-CZ70oOtp.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-BGvh3yIx.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-Xv6zfwXs.js → chunk-VR4S4FIN-B7AHEYYk.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-mOJNzbWl.js → chunk-WYO6CB5R-Dn9To_OI.js} +2 -2
- package/dist/assets/chunk-XXDRQBXY-DaBxG5gs.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-1-aKSu4o.js → chunk-YOTPTUD7-BYEgRBk3.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-OJ8veMpK.js → chunk-ZGVPDNZ5-C6YtZDU0.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-SR_Nq_PP.js → chunk-ZIRB5QZD-DMuYtnHF.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-P6N03G2R.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-B1_uLvMv.js +1 -0
- package/dist/assets/config-split-page-ps1Aod3g.js +1 -0
- package/dist/assets/confirm-dialog-DJSUNG33.js +5 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-NjVgz2Bw.js → cose-bilkent-JH36ORCC-Bc2Ex5Y3.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-B-H8Qp-n.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-B_17LDqD.js → cynefinDiagram-TSTJHNR4-DVysQoGz.js} +1 -1
- package/dist/assets/{dagre-CMe101gk.js → dagre-CMhQ1cAG.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-qo8nLb3B.js → dagre-VKFMJZFB-RYyWpPJZ.js} +1 -1
- package/dist/assets/desktop-update-config--zagjHic.js +1 -0
- package/dist/assets/{diagram-FQU43EPY-Ba3XIklC.js → diagram-FQU43EPY-BD6KONdF.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-CG45TcUx.js → diagram-G47NLZAW-CGB2ptRR.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-2F2HrwV-.js → diagram-NH7WQ7WH-DnkOI6cU.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-CXfWH9NZ.js → diagram-OA4YK3LP-DF82RZ7P.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-CH_4yepc.js → diagram-WEI45ONY-Be2v7Ck9.js} +1 -1
- package/dist/assets/{dist-CaYdVVeO.js → dist-BkTYNzm_.js} +1 -1
- package/dist/assets/{dist-BH7W5yCi.js → dist-DkR7_Dpl.js} +1 -1
- package/dist/assets/doc-browser-DahzJEWj.js +1 -0
- package/dist/assets/doc-browser-Q67TOGVS.js +1 -0
- package/dist/assets/doc-browser-context-BQim8SqD.js +1 -0
- package/dist/assets/{docx-preview-CoM4JK7_.js → docx-preview-BqwAjrj3.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-BwiG4Ea1.js → ebnfDiagram-CCIWWBDH-CP98OYk8.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-BML3hpnQ.js → erDiagram-Q63AITRT-ZLlx8xfs.js} +1 -1
- package/dist/assets/eventmodeling-45OFAUF4-YVtShyFA.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-BeKXabVO.js +1 -0
- package/dist/assets/{form-actions-0c0aw_bl.js → form-actions-B2-bpFie.js} +1 -1
- package/dist/assets/{ganttDiagram-NO4QXBWP-80enfWbD.js → ganttDiagram-NO4QXBWP-DXCDjHR2.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-jTSiBj-p.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-CVLqXr-b.js → gitGraphDiagram-IHSO6WYX-l2HWrTJp.js} +1 -1
- package/dist/assets/index-Ba_o5fu9.js +109 -0
- package/dist/assets/index-DSLK7zgR.css +1 -0
- package/dist/assets/info-DKCQHKI2-BIporNWb.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-Dyvs2t0i.js → infoDiagram-FWYZ7A6U-D-DjX-bn.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-sSnxDKfh.js → ishikawaDiagram-FXEZZL3T-y_Xy128F.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-D22V71Mf.js → journeyDiagram-5HDEW3XC-DJn5xYcQ.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-D3ds0p-g.js → kanban-definition-HUTT4EX6-DJVIOR21.js} +1 -1
- package/dist/assets/{line-CbyFs065.js → line-Cos7PIOj.js} +1 -1
- package/dist/assets/{linear-4DKtnZBS.js → linear-BtDLqtzF.js} +1 -1
- package/dist/assets/loader-circle-DyXZU92l.js +1 -0
- package/dist/assets/{map-CcZzEoz6.js → map-BKnQyvd0.js} +1 -1
- package/dist/assets/mcp-marketplace-page-B0dBE5CV.js +1 -0
- package/dist/assets/mcp-marketplace-page-w8panjZG.js +9 -0
- package/dist/assets/{mermaid-parser.core-DPmMOjXD.js → mermaid-parser.core-XUNZhr2W.js} +2 -2
- package/dist/assets/{mermaid.core-BSf-ddRa.js → mermaid.core-ySrvolIe.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-BUTwWPyx.js → mindmap-definition-LN4V7U3C-BypL9tei.js} +1 -1
- package/dist/assets/model-config-page-rrhFaque.js +1 -0
- package/dist/assets/{navigation-link-CVy0_kVl.js → navigation-link-mpHFXwRr.js} +2 -2
- package/dist/assets/{ordinal-BgLYtOZE.js → ordinal-CxxVWxYU.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-CuFMADV0.js +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-BEu_ZBjc.js → pegDiagram-2B236MQR-D-U2KBGv.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-XUeIXhM9.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-CAwAwuBd.js → pieDiagram-ENE6RG2P-CBi3GusJ.js} +1 -1
- package/dist/assets/plus-Dhb4KuMH.js +1 -0
- package/dist/assets/provider-scoped-model-input-CFsfWEt9.js +1 -0
- package/dist/assets/providers-config-page-D-TYFZsF.js +1 -0
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-CwE6F-_2.js → quadrantDiagram-ABIIQ3AL-H0ZuvnZL.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-D-NNGh1k.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-C67_uDaM.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-BZ8Yflnd.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-B7zO7RoK.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-R63PTgLz.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-xgLekU3B.js → railroadDiagram-RFXS5EU6-D7Y2EqSd.js} +1 -1
- package/dist/assets/react-BlXwvOLo.js +8 -0
- package/dist/assets/{refresh-cw-j2bl79Ea.js → refresh-cw-JFuyDj_P.js} +1 -1
- package/dist/assets/remote-BwVv_Qq-.js +1 -0
- package/dist/assets/{requirementDiagram-TGXJPOKE-CyVUzEX5.js → requirementDiagram-TGXJPOKE-BiXNX1NN.js} +1 -1
- package/dist/assets/rotate-cw-DjbbiIW_.js +1 -0
- package/dist/assets/runtime-config-page-Br9j9Vxe.js +1 -0
- package/dist/assets/{sankeyDiagram-HTMAVEWB-JK6bFmYB.js → sankeyDiagram-HTMAVEWB-qzDeLztW.js} +1 -1
- package/dist/assets/{save-BKNrtK81.js → save-BL8P8CLX.js} +1 -1
- package/dist/assets/{search-CkOm65W_.js → search-bZL75Pgc.js} +1 -1
- package/dist/assets/search-config-page-B3fvzMd1.js +1 -0
- package/dist/assets/secrets-config-page-ClwTxtXd.js +3 -0
- package/dist/assets/security-config-DmJw9QZA.js +1 -0
- package/dist/assets/{select-Ea7ffKCE.js → select-rUZ8nIZu.js} +2 -2
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-BR5IokXV.js → sequenceDiagram-DBY2YBRQ-BtRbPQtL.js} +1 -1
- package/dist/assets/{settings-2-CtyN3m_V.js → settings-2-BI4SCkxQ.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-SxG_YnMA.js → sizeCapture-X5ZJPWSS-CMYvM3SL.js} +1 -1
- package/dist/assets/skeleton-CVmEPG43.js +1 -0
- package/dist/assets/{src-vgz8E_-O.js → src-Bw-mzbQb.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-DD4OoYhn.js → stateDiagram-2N3HPSRC-BJ-mFeOz.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BE-HqxOK.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-BWkFeyCT.js → swimlanes-5IMT3BWC-BsucVOO2.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-Dr1H9LJH.js +8 -0
- package/dist/assets/{tag-chip-C9l4xsKp.js → tag-chip-BdI_yIOA.js} +1 -1
- package/dist/assets/{timeline-definition-FHXFAJF6-VTRPy6KA.js → timeline-definition-FHXFAJF6-Bicewlzo.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-npJ5dbqS.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-pYrBx6oa.js +1 -0
- package/dist/assets/{vennDiagram-L72KCM5P-Bvk42Pek.js → vennDiagram-L72KCM5P-BxOOnO9x.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-CmSRKLR8.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-DOFjx2s3.js → wardleyDiagram-EHGQE667-Cl7NltMv.js} +1 -1
- package/dist/assets/x-BcEayhV6.js +1 -0
- package/dist/assets/{xychartDiagram-FW5EYKEG-DY5yRTUc.js → xychartDiagram-FW5EYKEG-DiMIxQ7N.js} +1 -1
- package/dist/index.html +21 -22
- package/package.json +6 -6
- package/src/app/components/layout/app-layout.tsx +38 -2
- package/src/app/hooks/__tests__/use-app-event-consumers.test.ts +20 -0
- package/src/app/hooks/use-app-event-consumers.ts +21 -0
- package/src/app/presenters/app.presenter.ts +6 -0
- package/src/features/apps/components/__tests__/app-packages-panel.test.tsx +312 -0
- package/src/features/apps/components/__tests__/apps-panel.test.tsx +58 -0
- package/src/features/apps/components/app-artwork.tsx +49 -0
- package/src/features/apps/components/app-marketplace-catalog.tsx +332 -0
- package/src/features/apps/components/app-marketplace-cover.tsx +64 -0
- package/src/features/apps/components/app-marketplace-detail.tsx +161 -0
- package/src/features/apps/components/app-marketplace-dialog.tsx +152 -0
- package/src/features/apps/components/app-marketplace-operation.tsx +84 -0
- package/src/features/apps/components/app-package-card.tsx +417 -0
- package/src/features/apps/components/app-packages-panel.tsx +373 -0
- package/src/features/apps/components/apps-panel.tsx +31 -23
- package/src/features/apps/hooks/use-app-marketplace.test.ts +144 -0
- package/src/features/apps/hooks/use-app-marketplace.ts +65 -0
- package/src/features/apps/hooks/use-app-packages.ts +114 -0
- package/src/features/apps/index.ts +1 -0
- package/src/features/apps/managers/__tests__/app-package-operation-settlement.manager.test.ts +81 -0
- package/src/features/apps/managers/app-package-operation-settlement.manager.ts +80 -0
- package/src/features/apps/services/app-marketplace.service.ts +223 -0
- package/src/features/apps/types/app-marketplace.types.ts +75 -0
- package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +27 -4
- package/src/features/chat/components/layout/__tests__/chat-sidebar-session-area.test.tsx +36 -5
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +12 -13
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +49 -1
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +68 -7
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +25 -4
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +3 -0
- package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +24 -14
- package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +53 -0
- package/src/features/chat/features/conversation/hooks/__tests__/use-session-run-queue.test.tsx +18 -0
- package/src/features/chat/features/conversation/hooks/use-chat-composer-reference-intent.ts +4 -1
- package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +126 -32
- package/src/features/chat/features/conversation/hooks/use-session-run-queue.ts +12 -2
- package/src/features/chat/features/conversation/hooks/use-system-object-reference-select.ts +27 -0
- package/src/features/chat/features/conversation/utils/session-message-composer.utils.ts +5 -0
- package/src/features/chat/features/input/hooks/__tests__/use-chat-input-surface-state.test.tsx +102 -0
- package/src/features/chat/features/input/hooks/use-chat-input-surface-state.ts +71 -120
- package/src/features/chat/features/input/input-surface-plugins/__tests__/context-reference-plugin.test.ts +265 -18
- package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.types.ts +7 -2
- package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.utils.ts +124 -0
- package/src/features/chat/features/input/input-surface-plugins/context-reference-items.utils.ts +99 -15
- package/src/features/chat/features/input/input-surface-plugins/context-reference-plugin.utils.ts +143 -139
- package/src/features/chat/features/input/input-surface-plugins/panel-app-input-surface-items.utils.ts +116 -0
- package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +1 -1
- package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +84 -1
- package/src/features/chat/features/input/utils/chat-composer-token-protocol.utils.ts +10 -0
- package/src/features/chat/features/input/utils/chat-inline-token-composer.utils.ts +148 -0
- package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +55 -101
- package/src/features/chat/features/input/utils/chat-system-object-reference.utils.test.ts +44 -0
- package/src/features/chat/features/input/utils/chat-system-object-reference.utils.ts +46 -0
- package/src/features/chat/features/message/hooks/use-chat-inline-token-actions.ts +8 -1
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +155 -18
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-text-selection.test.tsx +12 -8
- package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +80 -62
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +9 -2
- package/src/features/chat/features/workspace/components/project-files/workspace-directory-tree.tsx +83 -13
- package/src/features/chat/features/workspace/components/project-files/workspace-project-tree-view.tsx +93 -0
- package/src/features/chat/features/workspace/hooks/use-workspace-explorer-layout.ts +8 -11
- package/src/features/chat/features/workspace/hooks/use-workspace-file-actions.ts +68 -46
- package/src/features/chat/features/workspace/stores/__tests__/workspace-project-tree.store.test.ts +38 -0
- package/src/features/chat/features/workspace/stores/workspace-project-tree.store.ts +160 -0
- package/src/features/chat/index.ts +2 -1
- package/src/features/chat/managers/__tests__/chat-composer-intent.manager.test.ts +29 -0
- package/src/features/chat/managers/chat-composer-intent.manager.ts +29 -2
- package/src/features/chat/managers/chat-draft-intent.manager.ts +18 -2
- package/src/features/chat/presenters/chat.presenter.ts +2 -2
- package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +6 -0
- package/src/features/chat/stores/chat-thread.store.ts +6 -0
- package/src/features/inbox/components/inbox-reader-dialog.test.tsx +38 -5
- package/src/features/inbox/components/inbox-reader-dialog.tsx +5 -3
- package/src/features/inbox/managers/inbox.manager.test.ts +28 -3
- package/src/features/inbox/managers/inbox.manager.ts +14 -4
- package/src/features/inbox/pages/inbox-page.test.ts +121 -2
- package/src/features/inbox/pages/inbox-page.tsx +5 -3
- package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +85 -1
- package/src/features/marketplace/hooks/__tests__/use-marketplace.test.tsx +44 -1
- package/src/features/marketplace/hooks/use-marketplace-item-actions.ts +23 -2
- package/src/features/marketplace/hooks/use-marketplace.ts +10 -0
- package/src/features/marketplace/index.ts +4 -0
- package/src/features/panel-apps/components/__tests__/panel-apps-list.test.tsx +1 -1
- package/src/features/panel-apps/components/panel-apps-list.tsx +1 -6
- package/src/features/panel-apps/index.ts +5 -1
- package/src/features/panel-apps/utils/__tests__/panel-app-doc-browser.utils.test.ts +13 -6
- package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +6 -3
- package/src/features/right-panel-resources/index.ts +1 -0
- package/src/features/right-panel-resources/utils/__tests__/right-panel-resource-uri.utils.test.ts +34 -0
- package/src/features/right-panel-resources/utils/right-panel-resource-uri.utils.ts +36 -4
- package/src/features/service-apps/components/service-apps-panel.tsx +3 -17
- package/src/features/system-status/components/__tests__/desktop-update-config.test.tsx +20 -1
- package/src/features/system-status/components/desktop-update-config.tsx +14 -13
- package/src/features/system-status/managers/__tests__/runtime-update.manager.test.ts +99 -0
- package/src/features/system-status/managers/runtime-update.manager.ts +22 -0
- package/src/features/system-status/stores/runtime-update.store.ts +1 -0
- package/src/platforms/desktop/components/desktop-app-shell.tsx +5 -0
- package/src/platforms/mobile/components/mobile-app-shell.tsx +9 -1
- package/src/shared/components/actions/__tests__/navigation-link.test.tsx +12 -0
- package/src/shared/components/actions/navigation-link.tsx +6 -3
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +34 -0
- package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +5 -0
- package/src/shared/components/doc-browser/doc-browser.tsx +11 -1
- package/src/shared/components/doc-browser/managers/doc-browser.manager.ts +13 -0
- package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +15 -0
- package/src/shared/components/ui/actions/icon-action-button.tsx +4 -2
- package/src/shared/components/ui/tabs.tsx +24 -1
- package/src/shared/hooks/use-server-path-watch.ts +42 -0
- package/src/shared/hooks/use-system-object-references.ts +22 -0
- package/src/shared/lib/api/server-path/server-path.types.ts +10 -0
- package/src/shared/lib/api/types.ts +13 -0
- package/src/shared/lib/api/utils/server-path.utils.ts +10 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +17 -9
- package/src/shared/lib/i18n/locales/en-US/desktop-update.json +7 -4
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +82 -0
- package/src/shared/lib/i18n/locales/en-US/marketplace.json +3 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +19 -11
- package/src/shared/lib/i18n/locales/zh-CN/desktop-update.json +7 -4
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +82 -0
- package/src/shared/lib/i18n/locales/zh-CN/marketplace.json +3 -0
- package/vite.config.ts +32 -1
- package/dist/assets/appearance-settings-page-BYbvl2wj.js +0 -1
- package/dist/assets/architecture-TIHT7OUA-Bjp9jf0h.js +0 -1
- package/dist/assets/channel-5T3pdR-s.js +0 -1
- package/dist/assets/chat-page-C5E-LLVd.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-DTZ3tGfE.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-HLGIHQ6k.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-Dl0m6Ni-.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-DcDnzGNX.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-BKXKMzKM.js +0 -1
- package/dist/assets/config-split-page-CA_a0AJ5.js +0 -1
- package/dist/assets/confirm-dialog-CxZfenjK.js +0 -5
- package/dist/assets/cynefin-VYW2F7L2-BWg7U2UD.js +0 -1
- package/dist/assets/desktop-update-config-BEKC8Ly9.js +0 -1
- package/dist/assets/doc-browser-Cl2ldE3f.js +0 -1
- package/dist/assets/doc-browser-DXCSd63E.js +0 -1
- package/dist/assets/doc-browser-context-FDPs3gJf.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-SB-J4tpq.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-BQ_u-eLM.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-DPxNwsFd.js +0 -1
- package/dist/assets/i18n-provider-DkITJNz8.js +0 -1
- package/dist/assets/index-CQ2LcI2p.css +0 -1
- package/dist/assets/index-CrdfvBVg.js +0 -107
- package/dist/assets/info-DKCQHKI2-DNlNGH90.js +0 -1
- package/dist/assets/loader-circle-DHtUxCIA.js +0 -1
- package/dist/assets/mcp-marketplace-page-Bc_jI5iH.js +0 -9
- package/dist/assets/mcp-marketplace-page-CzCieD9r.js +0 -1
- package/dist/assets/model-config-page-C4jw-pcj.js +0 -1
- package/dist/assets/packet-7NZHBO7P-BpeiqkBZ.js +0 -1
- package/dist/assets/pie-RZYD4A2V-Cy1yxsPd.js +0 -1
- package/dist/assets/plus-CG1RwZQq.js +0 -1
- package/dist/assets/provider-scoped-model-input-CmH4BFvc.js +0 -1
- package/dist/assets/providers-config-page-CJQjwzaw.js +0 -1
- package/dist/assets/radar-I7S5WNFK-CEcPKCj8.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-CW38eNDs.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-ByrylcXf.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-CNB6GwP-.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-x6hnqlBG.js +0 -1
- package/dist/assets/react-DjFBVA0n.js +0 -8
- package/dist/assets/remote-BIlpD3yL.js +0 -1
- package/dist/assets/rotate-cw-bKG8zH8M.js +0 -1
- package/dist/assets/runtime-config-page-B_x2Glz5.js +0 -1
- package/dist/assets/search-config-page-BaIijtmO.js +0 -1
- package/dist/assets/secrets-config-page-CJjtdFAl.js +0 -3
- package/dist/assets/security-config-DB8apj09.js +0 -1
- package/dist/assets/skeleton-Bt6zxcAB.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-ZC6dFORv.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-CRkh51Im.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-Bw0DSCH7.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-DFWBFcfh.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-CoWturk0.js +0 -1
- package/dist/assets/x-CowtCu9Z.js +0 -1
- /package/dist/assets/{array-NADKd9aU.js → array-BQVzeGRt.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-BuyuzJJL.js → chunk-KEIR6QF5-f9psyCXK.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-D_B2ZRNt.js → chunk-Y2CYZVJY-D1mAU_Po.js} +0 -0
- /package/dist/assets/{config-hints-BcfVUMij.js → config-hints-nV5HPOvq.js} +0 -0
- /package/dist/assets/{cytoscape.esm-BANTlgza.js → cytoscape.esm-0uDtdD0l.js} +0 -0
- /package/dist/assets/{defaultLocale-C4_L0aEs.js → defaultLocale-DSWXGgt0.js} +0 -0
- /package/dist/assets/{dist-DAPEIJbz.js → dist--ta5rX12.js} +0 -0
- /package/dist/assets/{graphlib-ChqXg0dI.js → graphlib-CQ6QV4yP.js} +0 -0
- /package/dist/assets/{host-capabilities-D9C4CBK5.js → host-capabilities-Tk038i04.js} +0 -0
- /package/dist/assets/{init-D8wZg9xq.js → init-Y6h9jGtZ.js} +0 -0
- /package/dist/assets/{jszip.min-CkbBfwAQ.js → jszip.min-8hyJpgpx.js} +0 -0
- /package/dist/assets/{katex-TZJFa0J_.js → katex-ARhY9PS1.js} +0 -0
- /package/dist/assets/{middleware-B3k-TSmZ.js → middleware-DXsbf9xI.js} +0 -0
- /package/dist/assets/{path-DodfxcX7.js → path-10BjdyLh.js} +0 -0
- /package/dist/assets/{rough.esm-CUaa1Rbe.js → rough.esm-DxgC_14r.js} +0 -0
- /package/dist/assets/{xlsx-CxByi7bR.js → xlsx-DrDuDNAa.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState
|
|
1
|
+
import { useState } from "react";
|
|
2
2
|
import type {
|
|
3
3
|
ServiceActionGrantView,
|
|
4
4
|
ServiceActionListView,
|
|
@@ -25,11 +25,7 @@ import { t } from "@/shared/lib/i18n";
|
|
|
25
25
|
|
|
26
26
|
type ServiceActionView = ServiceActionListView["actions"][number];
|
|
27
27
|
|
|
28
|
-
export function ServiceAppsPanel({
|
|
29
|
-
headerContent,
|
|
30
|
-
}: {
|
|
31
|
-
headerContent?: ReactNode;
|
|
32
|
-
}) {
|
|
28
|
+
export function ServiceAppsPanel() {
|
|
33
29
|
const serviceApps = useServiceApps();
|
|
34
30
|
const serviceActions = useServiceActions();
|
|
35
31
|
const serviceActionGrants = useServiceActionGrants();
|
|
@@ -92,17 +88,7 @@ export function ServiceAppsPanel({
|
|
|
92
88
|
|
|
93
89
|
return (
|
|
94
90
|
<div className="flex h-full min-h-0 flex-col bg-card text-card-foreground">
|
|
95
|
-
<div className="flex items-center justify-
|
|
96
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
97
|
-
{headerContent ?? (
|
|
98
|
-
<>
|
|
99
|
-
<Server className="h-4 w-4 text-primary" />
|
|
100
|
-
<div className="truncate text-sm font-semibold text-foreground">
|
|
101
|
-
{t("serviceAppsTitle")}
|
|
102
|
-
</div>
|
|
103
|
-
</>
|
|
104
|
-
)}
|
|
105
|
-
</div>
|
|
91
|
+
<div className="flex min-h-12 shrink-0 items-center justify-end border-b border-border/60 px-4 py-2">
|
|
106
92
|
<TooltipProvider delayDuration={250}>
|
|
107
93
|
<Tooltip>
|
|
108
94
|
<TooltipTrigger asChild>
|
|
@@ -11,6 +11,7 @@ const mocks = vi.hoisted(() => ({
|
|
|
11
11
|
start: vi.fn(),
|
|
12
12
|
stop: vi.fn(),
|
|
13
13
|
checkForUpdates: vi.fn(),
|
|
14
|
+
updateNow: vi.fn(),
|
|
14
15
|
downloadUpdate: vi.fn(),
|
|
15
16
|
applyDownloadedUpdate: vi.fn(),
|
|
16
17
|
updateChannel: vi.fn()
|
|
@@ -48,6 +49,7 @@ describe('DesktopUpdateConfig', () => {
|
|
|
48
49
|
mocks.start.mockReset();
|
|
49
50
|
mocks.stop.mockReset();
|
|
50
51
|
mocks.checkForUpdates.mockReset();
|
|
52
|
+
mocks.updateNow.mockReset();
|
|
51
53
|
mocks.downloadUpdate.mockReset();
|
|
52
54
|
mocks.applyDownloadedUpdate.mockReset();
|
|
53
55
|
mocks.updateChannel.mockReset();
|
|
@@ -101,12 +103,29 @@ describe('DesktopUpdateConfig', () => {
|
|
|
101
103
|
expect(screen.getByText('当前更新通道')).toBeTruthy();
|
|
102
104
|
expect(screen.getAllByText('Beta').length).toBeGreaterThan(0);
|
|
103
105
|
expect(screen.getByText('当前正在跟随 Beta 通道')).toBeTruthy();
|
|
104
|
-
expect(screen.getByText('
|
|
106
|
+
expect(screen.getByText('系统每两小时自动检查更新;是否开始更新由你确认。')).toBeTruthy();
|
|
105
107
|
expect(screen.queryByText('自动检查更新')).toBeNull();
|
|
106
108
|
expect(screen.queryByText('发现更新后自动后台下载')).toBeNull();
|
|
107
109
|
expect(screen.getByText('切回 Stable 后不会立刻强制降级;只有当 Stable 追平或超过当前版本时,才会继续提供 Stable 更新。')).toBeTruthy();
|
|
108
110
|
});
|
|
109
111
|
|
|
112
|
+
it('uses one update action instead of separate download and apply actions', async () => {
|
|
113
|
+
const user = userEvent.setup();
|
|
114
|
+
useRuntimeUpdateStore.setState((state) => ({
|
|
115
|
+
...state,
|
|
116
|
+
snapshot: state.snapshot ? { ...state.snapshot, status: 'update-available' } : null
|
|
117
|
+
}));
|
|
118
|
+
|
|
119
|
+
renderDesktopUpdateConfig();
|
|
120
|
+
|
|
121
|
+
expect(screen.queryByRole('button', { name: '下载更新' })).toBeNull();
|
|
122
|
+
const updateButton = screen.getByRole('button', { name: '立即更新' });
|
|
123
|
+
await user.click(updateButton);
|
|
124
|
+
expect(mocks.updateNow).toHaveBeenCalledTimes(1);
|
|
125
|
+
expect(mocks.downloadUpdate).not.toHaveBeenCalled();
|
|
126
|
+
expect(mocks.applyDownloadedUpdate).not.toHaveBeenCalled();
|
|
127
|
+
});
|
|
128
|
+
|
|
110
129
|
it('sends the newly selected release channel to the desktop update manager', async () => {
|
|
111
130
|
const user = userEvent.setup();
|
|
112
131
|
|
|
@@ -16,13 +16,15 @@ import {
|
|
|
16
16
|
type ReleaseNotesLocale,
|
|
17
17
|
type ReleaseNotesSection
|
|
18
18
|
} from '@/features/system-status/utils/update-release-notes.utils';
|
|
19
|
-
import {
|
|
19
|
+
import { RefreshCw, RotateCw } from 'lucide-react';
|
|
20
20
|
|
|
21
21
|
const STATUS_LABEL_KEYS: Record<string, string> = {
|
|
22
22
|
checking: 'desktopUpdatesStatusChecking',
|
|
23
23
|
'update-available': 'desktopUpdatesStatusAvailable',
|
|
24
24
|
downloading: 'desktopUpdatesStatusDownloading',
|
|
25
25
|
downloaded: 'desktopUpdatesStatusDownloaded',
|
|
26
|
+
applying: 'desktopUpdatesStatusApplying',
|
|
27
|
+
'restart-required': 'desktopUpdatesStatusRestartRequired',
|
|
26
28
|
'up-to-date': 'desktopUpdatesStatusUpToDate',
|
|
27
29
|
blocked: 'desktopUpdatesStatusBlocked',
|
|
28
30
|
failed: 'desktopUpdatesStatusFailed',
|
|
@@ -103,7 +105,7 @@ function getStatusLabel(snapshot: UpdateSnapshot): string {
|
|
|
103
105
|
return t(STATUS_LABEL_KEYS[snapshot.status] ?? 'desktopUpdatesStatusIdle');
|
|
104
106
|
}
|
|
105
107
|
function getStatusTone(status: string): string {
|
|
106
|
-
if (status === 'downloaded') {
|
|
108
|
+
if (status === 'downloaded' || status === 'restart-required') {
|
|
107
109
|
return 'bg-emerald-50 text-emerald-700 ring-emerald-100';
|
|
108
110
|
}
|
|
109
111
|
if (status === 'update-available' || status === 'downloading' || status === 'checking') {
|
|
@@ -218,9 +220,12 @@ export function DesktopUpdateConfig() {
|
|
|
218
220
|
const isChecking = busyAction === 'checking';
|
|
219
221
|
const isDownloading = busyAction === 'downloading';
|
|
220
222
|
const isApplying = busyAction === 'applying';
|
|
223
|
+
const isUpdating = busyAction === 'updating';
|
|
221
224
|
const isSwitchingChannel = busyAction === 'switching-channel';
|
|
222
|
-
const
|
|
223
|
-
|
|
225
|
+
const canUpdate = (snapshot.status === 'update-available' || snapshot.status === 'downloaded')
|
|
226
|
+
&& !isDownloading
|
|
227
|
+
&& !isApplying
|
|
228
|
+
&& !isUpdating;
|
|
224
229
|
const overviewStats = [
|
|
225
230
|
[t('runtimeUpdatesHostVersion'), formatVersion(snapshot.hostVersion)],
|
|
226
231
|
[t('desktopUpdatesCurrentBundleVersion'), formatVersion(snapshot.currentVersion)],
|
|
@@ -232,7 +237,7 @@ export function DesktopUpdateConfig() {
|
|
|
232
237
|
<SettingsPage
|
|
233
238
|
title={t('runtimeUpdatesPageTitle')}
|
|
234
239
|
description={t('runtimeUpdatesPageDescription')}
|
|
235
|
-
actions={<Button variant='outline' onClick={() => void runtimeUpdateManager.checkForUpdates()} disabled={isChecking || isDownloading || isApplying}><RefreshCw className={cn('mr-2 h-4 w-4', isChecking && 'animate-spin')} />{t('desktopUpdatesCheckNow')}</Button>}
|
|
240
|
+
actions={<Button variant='outline' onClick={() => void runtimeUpdateManager.checkForUpdates()} disabled={isChecking || isDownloading || isApplying || isUpdating}><RefreshCw className={cn('mr-2 h-4 w-4', isChecking && 'animate-spin')} />{t('desktopUpdatesCheckNow')}</Button>}
|
|
236
241
|
>
|
|
237
242
|
<SettingsSection title={t('desktopUpdatesOverviewTitle')} description={t('desktopUpdatesOverviewDescription')}>
|
|
238
243
|
<SettingsGroup>
|
|
@@ -278,7 +283,7 @@ export function DesktopUpdateConfig() {
|
|
|
278
283
|
layout='stacked'
|
|
279
284
|
>
|
|
280
285
|
<div className='space-y-2'>
|
|
281
|
-
<Select value={snapshot.channel} disabled={isSwitchingChannel || isChecking || isDownloading || isApplying} onValueChange={(value) => void runtimeUpdateManager.updateChannel(value as UpdateSnapshot['channel'])}>
|
|
286
|
+
<Select value={snapshot.channel} disabled={isSwitchingChannel || isChecking || isDownloading || isApplying || isUpdating} onValueChange={(value) => void runtimeUpdateManager.updateChannel(value as UpdateSnapshot['channel'])}>
|
|
282
287
|
<SelectTrigger className='w-full max-w-sm'>
|
|
283
288
|
<SelectValue placeholder={t('desktopUpdatesReleaseChannel')} />
|
|
284
289
|
</SelectTrigger>
|
|
@@ -295,16 +300,12 @@ export function DesktopUpdateConfig() {
|
|
|
295
300
|
<SettingsSection title={t('desktopUpdatesActionsTitle')} description={t('runtimeUpdatesActionsDescription')}>
|
|
296
301
|
<SettingsGroup>
|
|
297
302
|
<div className='flex flex-wrap items-center gap-3 p-4'>
|
|
298
|
-
<Button variant='outline' onClick={() => void runtimeUpdateManager.checkForUpdates()} disabled={isChecking || isDownloading || isApplying}>
|
|
303
|
+
<Button variant='outline' onClick={() => void runtimeUpdateManager.checkForUpdates()} disabled={isChecking || isDownloading || isApplying || isUpdating}>
|
|
299
304
|
<RefreshCw className={cn('mr-2 h-4 w-4', isChecking && 'animate-spin')} />
|
|
300
305
|
{t('desktopUpdatesCheckNow')}
|
|
301
306
|
</Button>
|
|
302
|
-
<Button onClick={() => void runtimeUpdateManager.
|
|
303
|
-
<
|
|
304
|
-
{t('desktopUpdatesDownloadNow')}
|
|
305
|
-
</Button>
|
|
306
|
-
<Button variant='secondary' onClick={() => void runtimeUpdateManager.applyDownloadedUpdate()} disabled={!canApply}>
|
|
307
|
-
<RotateCw className={cn('mr-2 h-4 w-4', isApplying && 'animate-spin')} />
|
|
307
|
+
<Button onClick={() => void runtimeUpdateManager.updateNow()} disabled={!canUpdate}>
|
|
308
|
+
<RotateCw className={cn('mr-2 h-4 w-4', isUpdating && 'animate-spin')} />
|
|
308
309
|
{t('runtimeUpdatesApplyNow')}
|
|
309
310
|
</Button>
|
|
310
311
|
</div>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { UpdateSnapshot } from '@nextclaw/shared';
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { RuntimeUpdateManager } from '@/features/system-status/managers/runtime-update.manager';
|
|
4
|
+
import { useRuntimeUpdateStore } from '@/features/system-status/stores/runtime-update.store';
|
|
5
|
+
|
|
6
|
+
const mocks = vi.hoisted(() => ({
|
|
7
|
+
applyRuntimeUpdate: vi.fn(),
|
|
8
|
+
checkRuntimeUpdate: vi.fn(),
|
|
9
|
+
downloadRuntimeUpdate: vi.fn(),
|
|
10
|
+
fetchRuntimeUpdate: vi.fn(),
|
|
11
|
+
updateRuntimeUpdateChannel: vi.fn()
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
vi.mock('@/shared/lib/api', () => mocks);
|
|
15
|
+
|
|
16
|
+
const createSnapshot = (patch: Partial<UpdateSnapshot> = {}): UpdateSnapshot => ({
|
|
17
|
+
status: 'update-available',
|
|
18
|
+
installationKind: 'npm-runtime-bundle',
|
|
19
|
+
channel: 'stable',
|
|
20
|
+
hostVersion: '0.30.0',
|
|
21
|
+
currentVersion: '0.30.0',
|
|
22
|
+
availableVersion: '0.31.0',
|
|
23
|
+
downloadedVersion: null,
|
|
24
|
+
minimumHostVersion: null,
|
|
25
|
+
releaseNotesUrl: null,
|
|
26
|
+
lastCheckedAt: null,
|
|
27
|
+
progress: null,
|
|
28
|
+
canApplyInApp: false,
|
|
29
|
+
requiresRestart: false,
|
|
30
|
+
blockReason: null,
|
|
31
|
+
recoveryCommand: null,
|
|
32
|
+
errorMessage: null,
|
|
33
|
+
...patch
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('RuntimeUpdateManager', () => {
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
vi.clearAllMocks();
|
|
39
|
+
useRuntimeUpdateStore.setState({
|
|
40
|
+
supported: false,
|
|
41
|
+
initialized: false,
|
|
42
|
+
busyAction: null,
|
|
43
|
+
snapshot: null
|
|
44
|
+
});
|
|
45
|
+
mocks.fetchRuntimeUpdate.mockResolvedValue(createSnapshot());
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('downloads and applies an available update from one user action', async () => {
|
|
49
|
+
const downloaded = createSnapshot({
|
|
50
|
+
status: 'downloaded',
|
|
51
|
+
downloadedVersion: '0.31.0',
|
|
52
|
+
canApplyInApp: true
|
|
53
|
+
});
|
|
54
|
+
const applied = createSnapshot({
|
|
55
|
+
status: 'restart-required',
|
|
56
|
+
availableVersion: null,
|
|
57
|
+
downloadedVersion: null,
|
|
58
|
+
requiresRestart: true
|
|
59
|
+
});
|
|
60
|
+
mocks.downloadRuntimeUpdate.mockResolvedValue(downloaded);
|
|
61
|
+
mocks.applyRuntimeUpdate.mockResolvedValue(applied);
|
|
62
|
+
const manager = new RuntimeUpdateManager();
|
|
63
|
+
await manager.start();
|
|
64
|
+
|
|
65
|
+
await manager.updateNow();
|
|
66
|
+
|
|
67
|
+
expect(mocks.downloadRuntimeUpdate).toHaveBeenCalledTimes(1);
|
|
68
|
+
expect(mocks.applyRuntimeUpdate).toHaveBeenCalledTimes(1);
|
|
69
|
+
expect(useRuntimeUpdateStore.getState()).toMatchObject({
|
|
70
|
+
busyAction: null,
|
|
71
|
+
snapshot: applied
|
|
72
|
+
});
|
|
73
|
+
manager.stop();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('resumes a downloaded update without downloading it again', async () => {
|
|
77
|
+
const downloaded = createSnapshot({
|
|
78
|
+
status: 'downloaded',
|
|
79
|
+
downloadedVersion: '0.31.0',
|
|
80
|
+
canApplyInApp: true
|
|
81
|
+
});
|
|
82
|
+
const applied = createSnapshot({
|
|
83
|
+
status: 'restart-required',
|
|
84
|
+
availableVersion: null,
|
|
85
|
+
downloadedVersion: null,
|
|
86
|
+
requiresRestart: true
|
|
87
|
+
});
|
|
88
|
+
mocks.fetchRuntimeUpdate.mockResolvedValue(downloaded);
|
|
89
|
+
mocks.applyRuntimeUpdate.mockResolvedValue(applied);
|
|
90
|
+
const manager = new RuntimeUpdateManager();
|
|
91
|
+
await manager.start();
|
|
92
|
+
|
|
93
|
+
await manager.updateNow();
|
|
94
|
+
|
|
95
|
+
expect(mocks.downloadRuntimeUpdate).not.toHaveBeenCalled();
|
|
96
|
+
expect(mocks.applyRuntimeUpdate).toHaveBeenCalledTimes(1);
|
|
97
|
+
manager.stop();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -208,6 +208,28 @@ export class RuntimeUpdateManager {
|
|
|
208
208
|
}
|
|
209
209
|
};
|
|
210
210
|
|
|
211
|
+
updateNow = async () => {
|
|
212
|
+
const initialSnapshot = useRuntimeUpdateStore.getState().snapshot;
|
|
213
|
+
if (initialSnapshot?.status !== 'update-available' && initialSnapshot?.status !== 'downloaded') {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
await this.runSnapshotCommand('updating', t('runtimeUpdatesUpdateFailed'), async (source) => {
|
|
219
|
+
const downloadedSnapshot = initialSnapshot.status === 'downloaded'
|
|
220
|
+
? initialSnapshot
|
|
221
|
+
: await source.downloadUpdate();
|
|
222
|
+
useRuntimeUpdateStore.setState({ snapshot: downloadedSnapshot });
|
|
223
|
+
if (downloadedSnapshot.status !== 'downloaded') {
|
|
224
|
+
return downloadedSnapshot;
|
|
225
|
+
}
|
|
226
|
+
return await source.applyDownloadedUpdate();
|
|
227
|
+
});
|
|
228
|
+
} catch {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
211
233
|
updateChannel = async (channel: UpdateSnapshot['channel']) => {
|
|
212
234
|
const currentChannel = useRuntimeUpdateStore.getState().snapshot?.channel;
|
|
213
235
|
if (currentChannel === channel) {
|
|
@@ -10,6 +10,7 @@ import { isWindowsDesktopHost } from "@/platforms/desktop/utils/desktop-host.uti
|
|
|
10
10
|
import { MobileBottomNav } from "@/platforms/mobile";
|
|
11
11
|
import type { DocBrowserCustomTabRenderers } from "@/shared/components/doc-browser/doc-browser-renderer.types";
|
|
12
12
|
import type { DocBrowserDockControls } from "@/shared/components/doc-browser/doc-browser-context";
|
|
13
|
+
import type { DocBrowserTabMenuGroupsResolver } from "@/shared/components/doc-browser/doc-browser";
|
|
13
14
|
import { cn } from "@/shared/lib/utils";
|
|
14
15
|
import { useViewportLayoutStore } from "@/app/stores/viewport-layout.store";
|
|
15
16
|
import { SIDEBAR_RAIL_WIDTH_PX } from "@/app/components/layout/sidebar-rail.styles";
|
|
@@ -26,6 +27,7 @@ type DesktopAppShellProps = {
|
|
|
26
27
|
docBrowserMode: "floating" | "docked";
|
|
27
28
|
docBrowserDockControls?: DocBrowserDockControls;
|
|
28
29
|
docBrowserRenderers?: DocBrowserCustomTabRenderers;
|
|
30
|
+
docBrowserTabMenuGroups?: DocBrowserTabMenuGroupsResolver;
|
|
29
31
|
sideDock?: React.ReactNode;
|
|
30
32
|
children: React.ReactNode;
|
|
31
33
|
};
|
|
@@ -37,6 +39,7 @@ export function DesktopAppShell({
|
|
|
37
39
|
docBrowserMode,
|
|
38
40
|
docBrowserDockControls,
|
|
39
41
|
docBrowserRenderers = {},
|
|
42
|
+
docBrowserTabMenuGroups,
|
|
40
43
|
sideDock,
|
|
41
44
|
children,
|
|
42
45
|
}: DesktopAppShellProps) {
|
|
@@ -91,6 +94,7 @@ export function DesktopAppShell({
|
|
|
91
94
|
<DocBrowser
|
|
92
95
|
customTabRenderers={docBrowserRenderers}
|
|
93
96
|
dockControls={docBrowserDockControls}
|
|
97
|
+
getTabMenuGroups={docBrowserTabMenuGroups}
|
|
94
98
|
/>
|
|
95
99
|
</Suspense>
|
|
96
100
|
) : null}
|
|
@@ -103,6 +107,7 @@ export function DesktopAppShell({
|
|
|
103
107
|
<DocBrowser
|
|
104
108
|
customTabRenderers={docBrowserRenderers}
|
|
105
109
|
dockControls={docBrowserDockControls}
|
|
110
|
+
getTabMenuGroups={docBrowserTabMenuGroups}
|
|
106
111
|
/>
|
|
107
112
|
</Suspense>
|
|
108
113
|
) : null}
|
|
@@ -7,6 +7,7 @@ import { MobileBottomNav } from "@/platforms/mobile/components/mobile-bottom-nav
|
|
|
7
7
|
import { MobileTopbar } from "@/platforms/mobile/components/mobile-topbar";
|
|
8
8
|
import type { DocBrowserCustomTabRenderers } from "@/shared/components/doc-browser/doc-browser-renderer.types";
|
|
9
9
|
import type { DocBrowserDockControls } from "@/shared/components/doc-browser/doc-browser-context";
|
|
10
|
+
import type { DocBrowserTabMenuGroupsResolver } from "@/shared/components/doc-browser/doc-browser";
|
|
10
11
|
|
|
11
12
|
const DocBrowser = lazy(async () => ({
|
|
12
13
|
default: (await import("@/shared/components/doc-browser/doc-browser")).DocBrowser,
|
|
@@ -17,6 +18,7 @@ type MobileAppShellProps = {
|
|
|
17
18
|
isDocBrowserOpen: boolean;
|
|
18
19
|
docBrowserDockControls?: DocBrowserDockControls;
|
|
19
20
|
docBrowserRenderers?: DocBrowserCustomTabRenderers;
|
|
21
|
+
docBrowserTabMenuGroups?: DocBrowserTabMenuGroupsResolver;
|
|
20
22
|
topbarLeadingInset?: string;
|
|
21
23
|
children: React.ReactNode;
|
|
22
24
|
};
|
|
@@ -26,6 +28,7 @@ export function MobileAppShell({
|
|
|
26
28
|
isDocBrowserOpen,
|
|
27
29
|
docBrowserDockControls,
|
|
28
30
|
docBrowserRenderers = {},
|
|
31
|
+
docBrowserTabMenuGroups,
|
|
29
32
|
topbarLeadingInset,
|
|
30
33
|
children,
|
|
31
34
|
}: MobileAppShellProps) {
|
|
@@ -48,7 +51,12 @@ export function MobileAppShell({
|
|
|
48
51
|
{showBottomNav ? <MobileBottomNav /> : null}
|
|
49
52
|
{isDocBrowserOpen ? (
|
|
50
53
|
<Suspense fallback={null}>
|
|
51
|
-
<DocBrowser
|
|
54
|
+
<DocBrowser
|
|
55
|
+
customTabRenderers={docBrowserRenderers}
|
|
56
|
+
displayMode="fullscreen"
|
|
57
|
+
dockControls={docBrowserDockControls}
|
|
58
|
+
getTabMenuGroups={docBrowserTabMenuGroups}
|
|
59
|
+
/>
|
|
52
60
|
</Suspense>
|
|
53
61
|
) : null}
|
|
54
62
|
</div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createRef } from "react";
|
|
1
2
|
import { fireEvent, render, screen } from "@testing-library/react";
|
|
2
3
|
import { MemoryRouter, Route, Routes } from "react-router-dom";
|
|
3
4
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
@@ -55,4 +56,15 @@ describe("NavigationLink", () => {
|
|
|
55
56
|
expect(screen.getByText("Session route")).toBeTruthy();
|
|
56
57
|
expect(mocks.openExternalUrl).not.toHaveBeenCalled();
|
|
57
58
|
});
|
|
59
|
+
|
|
60
|
+
it("forwards refs to the rendered anchor for asChild consumers", () => {
|
|
61
|
+
const ref = createRef<HTMLAnchorElement>();
|
|
62
|
+
render(
|
|
63
|
+
<NavigationLink ref={ref} href="https://docs.nextclaw.io/" external>
|
|
64
|
+
View docs
|
|
65
|
+
</NavigationLink>,
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
expect(ref.current).toBe(screen.getByRole("link", { name: "View docs" }));
|
|
69
|
+
});
|
|
58
70
|
});
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
MouseEvent,
|
|
4
4
|
ReactNode,
|
|
5
5
|
} from "react";
|
|
6
|
+
import { forwardRef } from "react";
|
|
6
7
|
import { ExternalLink as ExternalLinkIcon, type LucideIcon } from "lucide-react";
|
|
7
8
|
import { Link } from "react-router-dom";
|
|
8
9
|
import { hostCapabilityManager } from "@/shared/lib/host-capabilities";
|
|
@@ -62,7 +63,7 @@ function resolveExternalHttpUrl(href: string): string | null {
|
|
|
62
63
|
* Internal links use client-side routing; external links delegate ordinary
|
|
63
64
|
* clicks to the desktop host when one is available.
|
|
64
65
|
*/
|
|
65
|
-
export function NavigationLink({
|
|
66
|
+
export const NavigationLink = forwardRef<HTMLAnchorElement, NavigationLinkProps>(function NavigationLink({
|
|
66
67
|
children,
|
|
67
68
|
className,
|
|
68
69
|
external = false,
|
|
@@ -74,7 +75,7 @@ export function NavigationLink({
|
|
|
74
75
|
size = "sm",
|
|
75
76
|
target,
|
|
76
77
|
...props
|
|
77
|
-
}
|
|
78
|
+
}, ref) {
|
|
78
79
|
const Icon = icon === undefined && external ? ExternalLinkIcon : icon;
|
|
79
80
|
const linkClassName = cn(
|
|
80
81
|
"inline-flex items-center rounded-sm font-medium text-primary underline-offset-4 transition-colors hover:text-primary-hover hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25",
|
|
@@ -98,6 +99,7 @@ export function NavigationLink({
|
|
|
98
99
|
if (!external) {
|
|
99
100
|
return (
|
|
100
101
|
<Link
|
|
102
|
+
ref={ref}
|
|
101
103
|
{...props}
|
|
102
104
|
to={href}
|
|
103
105
|
target={target}
|
|
@@ -112,6 +114,7 @@ export function NavigationLink({
|
|
|
112
114
|
|
|
113
115
|
return (
|
|
114
116
|
<a
|
|
117
|
+
ref={ref}
|
|
115
118
|
{...props}
|
|
116
119
|
href={href}
|
|
117
120
|
target={target ?? "_blank"}
|
|
@@ -133,4 +136,4 @@ export function NavigationLink({
|
|
|
133
136
|
{content}
|
|
134
137
|
</a>
|
|
135
138
|
);
|
|
136
|
-
}
|
|
139
|
+
});
|
|
@@ -571,6 +571,40 @@ describe("DocBrowser floating interactions", () => {
|
|
|
571
571
|
expect(onDragStart).toHaveBeenCalledTimes(1);
|
|
572
572
|
});
|
|
573
573
|
|
|
574
|
+
it("opens the same tab action from right click and the more button", () => {
|
|
575
|
+
const onAddToChat = vi.fn();
|
|
576
|
+
|
|
577
|
+
render(
|
|
578
|
+
<DocBrowserTabStrip
|
|
579
|
+
tabs={docBrowserState.tabs}
|
|
580
|
+
activeTabId="docs"
|
|
581
|
+
canGoBack={false}
|
|
582
|
+
canGoForward={false}
|
|
583
|
+
isDocked={true}
|
|
584
|
+
isFullscreen={false}
|
|
585
|
+
onGoBack={vi.fn()}
|
|
586
|
+
onGoForward={vi.fn()}
|
|
587
|
+
onOpenNewTab={vi.fn()}
|
|
588
|
+
onSetActiveTab={vi.fn()}
|
|
589
|
+
onCloseTab={vi.fn()}
|
|
590
|
+
onClose={vi.fn()}
|
|
591
|
+
onDragStart={vi.fn()}
|
|
592
|
+
onToggleMode={vi.fn()}
|
|
593
|
+
getTabMenuGroups={() => [{
|
|
594
|
+
key: "chat",
|
|
595
|
+
items: [{ key: "add", label: "Add to Chat", onSelect: onAddToChat }],
|
|
596
|
+
}]}
|
|
597
|
+
/>,
|
|
598
|
+
);
|
|
599
|
+
|
|
600
|
+
fireEvent.contextMenu(screen.getByRole("button", { name: "Docs" }));
|
|
601
|
+
fireEvent.click(screen.getByRole("menuitem", { name: "Add to Chat" }));
|
|
602
|
+
fireEvent.click(screen.getByRole("button", { name: "More tab actions" }));
|
|
603
|
+
fireEvent.click(screen.getByRole("menuitem", { name: "Add to Chat" }));
|
|
604
|
+
|
|
605
|
+
expect(onAddToChat).toHaveBeenCalledTimes(2);
|
|
606
|
+
});
|
|
607
|
+
|
|
574
608
|
it("keeps the floating panel left edge stable when resizing from the right", () => {
|
|
575
609
|
docBrowserState.mode = "floating";
|
|
576
610
|
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
X,
|
|
11
11
|
} from "lucide-react";
|
|
12
12
|
import type { DocBrowserDockState, DocBrowserTab } from "./doc-browser-context";
|
|
13
|
+
import type { ContextMenuGroup } from "@/shared/components/ui/context-menu/context-menu";
|
|
13
14
|
import {
|
|
14
15
|
CompactTabStrip,
|
|
15
16
|
type CompactTabStripAction,
|
|
@@ -35,6 +36,7 @@ type DocBrowserTabStripProps = {
|
|
|
35
36
|
onClose: () => void;
|
|
36
37
|
onDragStart: (event: PointerEvent<HTMLElement>) => void;
|
|
37
38
|
onToggleMode: () => void;
|
|
39
|
+
getTabMenuGroups?: (tab: DocBrowserTab) => readonly ContextMenuGroup[] | undefined;
|
|
38
40
|
};
|
|
39
41
|
|
|
40
42
|
function shouldBlockHeaderDrag(target: EventTarget | null): boolean {
|
|
@@ -60,6 +62,7 @@ export function DocBrowserTabStrip({
|
|
|
60
62
|
onClose,
|
|
61
63
|
onDragStart,
|
|
62
64
|
onToggleMode,
|
|
65
|
+
getTabMenuGroups,
|
|
63
66
|
}: DocBrowserTabStripProps) {
|
|
64
67
|
const backLabel = t("docBrowserBack");
|
|
65
68
|
const closeLabel = t("docBrowserClose");
|
|
@@ -81,6 +84,8 @@ export function DocBrowserTabStrip({
|
|
|
81
84
|
closePlacement: "trailing",
|
|
82
85
|
onSelect: () => onSetActiveTab(tab.id),
|
|
83
86
|
onClose: () => onCloseTab(tab.id),
|
|
87
|
+
menuLabel: t("docBrowserTabMoreActions"),
|
|
88
|
+
menuGroups: getTabMenuGroups?.(tab),
|
|
84
89
|
}));
|
|
85
90
|
const actions: CompactTabStripAction[] = [
|
|
86
91
|
{ key: "back", disabled: !canGoBack, icon: <ArrowLeft className="h-3.5 w-3.5" />, label: backLabel, onClick: onGoBack },
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
import { ResizableRightPanel } from '@/shared/components/resizable-right-panel/resizable-right-panel';
|
|
29
29
|
import { cn } from '@/shared/lib/utils';
|
|
30
30
|
import { t } from '@/shared/lib/i18n';
|
|
31
|
+
import type { ContextMenuGroup } from '@/shared/components/ui/context-menu/context-menu';
|
|
31
32
|
import { GripVertical } from 'lucide-react';
|
|
32
33
|
import {
|
|
33
34
|
DOC_BROWSER_DOCKED_MAX_WIDTH,
|
|
@@ -38,8 +39,11 @@ type DocBrowserProps = {
|
|
|
38
39
|
customTabRenderers?: DocBrowserCustomTabRenderers;
|
|
39
40
|
displayMode?: 'desktop' | 'fullscreen';
|
|
40
41
|
dockControls?: DocBrowserDockControls;
|
|
42
|
+
getTabMenuGroups?: (tab: DocBrowserTab) => readonly ContextMenuGroup[] | undefined;
|
|
41
43
|
};
|
|
42
44
|
|
|
45
|
+
export type DocBrowserTabMenuGroupsResolver = NonNullable<DocBrowserProps['getTabMenuGroups']>;
|
|
46
|
+
|
|
43
47
|
type FloatingPanelInteraction = {
|
|
44
48
|
startX: number;
|
|
45
49
|
startY: number;
|
|
@@ -160,7 +164,12 @@ function useDocBrowserAddressBar({
|
|
|
160
164
|
};
|
|
161
165
|
}
|
|
162
166
|
|
|
163
|
-
export function DocBrowser({
|
|
167
|
+
export function DocBrowser({
|
|
168
|
+
customTabRenderers = {},
|
|
169
|
+
displayMode = 'desktop',
|
|
170
|
+
dockControls,
|
|
171
|
+
getTabMenuGroups,
|
|
172
|
+
}: DocBrowserProps) {
|
|
164
173
|
const {
|
|
165
174
|
isOpen,
|
|
166
175
|
mode,
|
|
@@ -367,6 +376,7 @@ export function DocBrowser({ customTabRenderers = {}, displayMode = 'desktop', d
|
|
|
367
376
|
onClose={close}
|
|
368
377
|
onDragStart={startFloatDrag}
|
|
369
378
|
onToggleMode={toggleMode}
|
|
379
|
+
getTabMenuGroups={getTabMenuGroups}
|
|
370
380
|
/>
|
|
371
381
|
|
|
372
382
|
<DocBrowserAddressToolbar
|
|
@@ -267,6 +267,19 @@ export class DocBrowserManager {
|
|
|
267
267
|
this.onRightPanelOpened?.();
|
|
268
268
|
};
|
|
269
269
|
|
|
270
|
+
readonly reloadByDedupeKeys = (dedupeKeys: readonly string[]): void => {
|
|
271
|
+
const targets = new Set(dedupeKeys);
|
|
272
|
+
if (targets.size === 0) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
this.setSnapshot((prev) => ({
|
|
276
|
+
...prev,
|
|
277
|
+
tabs: prev.tabs.map((tab) => targets.has(tab.dedupeKey ?? "")
|
|
278
|
+
? { ...tab, navVersion: tab.navVersion + 1 }
|
|
279
|
+
: tab),
|
|
280
|
+
}));
|
|
281
|
+
};
|
|
282
|
+
|
|
270
283
|
readonly openNewTab = (): void => {
|
|
271
284
|
this.open(undefined, { kind: DOC_BROWSER_HOME_TAB_KIND, newTab: true });
|
|
272
285
|
};
|
|
@@ -34,6 +34,21 @@ describe('IconActionButton', () => {
|
|
|
34
34
|
expect(button.className).toContain('hover:bg-[var(--interaction-hover)]');
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
+
it('uses surface-relative feedback without introducing a new surface', () => {
|
|
38
|
+
render(
|
|
39
|
+
<IconActionButton
|
|
40
|
+
tone="surface"
|
|
41
|
+
icon={<span data-testid="icon" />}
|
|
42
|
+
label="Add project"
|
|
43
|
+
/>,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const button = screen.getByRole('button', { name: 'Add project' });
|
|
47
|
+
expect(button.className).toContain('hover:bg-gray-200/60');
|
|
48
|
+
expect(button.className).toContain('hover:text-gray-900');
|
|
49
|
+
expect(button.className).toContain('active:bg-gray-200/80');
|
|
50
|
+
});
|
|
51
|
+
|
|
37
52
|
it('ignores restored pointer focus while preserving keyboard tooltip focus', () => {
|
|
38
53
|
render(
|
|
39
54
|
<IconActionButton
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
import { cn } from '@/shared/lib/utils';
|
|
9
9
|
|
|
10
10
|
type IconActionButtonSize = 'sm' | 'md' | 'lg';
|
|
11
|
-
type IconActionButtonTone = 'default' | 'strong';
|
|
11
|
+
type IconActionButtonTone = 'default' | 'surface' | 'strong';
|
|
12
12
|
|
|
13
13
|
type IconActionButtonProps = Omit<
|
|
14
14
|
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
@@ -17,7 +17,7 @@ type IconActionButtonProps = Omit<
|
|
|
17
17
|
icon: React.ReactNode;
|
|
18
18
|
label: string;
|
|
19
19
|
size?: IconActionButtonSize;
|
|
20
|
-
/** default:
|
|
20
|
+
/** default: global interaction hover. surface: relative feedback on the current surface. strong: denser feedback for nested hover surfaces. */
|
|
21
21
|
tone?: IconActionButtonTone;
|
|
22
22
|
tooltip?: string | false | null;
|
|
23
23
|
tooltipSide?: 'top' | 'right' | 'bottom' | 'left';
|
|
@@ -32,6 +32,8 @@ const SIZE_CLASS: Record<IconActionButtonSize, string> = {
|
|
|
32
32
|
const TONE_CLASS: Record<IconActionButtonTone, string> = {
|
|
33
33
|
default:
|
|
34
34
|
'text-muted-foreground hover:bg-[var(--interaction-hover)] hover:text-accent-foreground disabled:text-muted-foreground/45 disabled:hover:bg-transparent disabled:hover:text-muted-foreground/45',
|
|
35
|
+
surface:
|
|
36
|
+
'text-muted-foreground hover:bg-gray-200/60 hover:text-gray-900 active:bg-gray-200/80 disabled:text-muted-foreground/45 disabled:hover:bg-transparent disabled:hover:text-muted-foreground/45',
|
|
35
37
|
strong:
|
|
36
38
|
'text-muted-foreground hover:bg-black/10 hover:text-foreground disabled:text-muted-foreground/45 disabled:hover:bg-transparent disabled:hover:text-muted-foreground/45',
|
|
37
39
|
};
|