@nextclaw/ui 0.15.4 → 0.15.5
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 +17 -0
- package/dist/assets/abnfDiagram-VRR7QNED-BYpK0F5F.js +1 -0
- package/dist/assets/{aiden0z-pptx-renderer.es-Bd99vut2.js → aiden0z-pptx-renderer.es-D87ywFdC.js} +1 -1
- package/dist/assets/{api-BOXOrpcJ.js → api-IlX_CbwU.js} +2 -2
- package/dist/assets/app-presenter-provider-Bbl_MVbg.js +106 -0
- package/dist/assets/{appearance-settings-page-fLIJbx1C.js → appearance-settings-page-80fLa4-9.js} +1 -1
- package/dist/assets/arc-DFELHWM2.js +1 -0
- package/dist/assets/architecture-TIHT7OUA-ClwVFq-K.js +1 -0
- package/dist/assets/architectureDiagram-ZJ3FMSHR-CvRhdovL.js +36 -0
- package/dist/assets/array-BqYdCIE6.js +1 -0
- package/dist/assets/blockDiagram-677ZJIJ3-DVYNkbR_.js +132 -0
- package/dist/assets/{book-open-DWUjS6aW.js → book-open-CN7Shpij.js} +1 -1
- package/dist/assets/c4Diagram-LMCZKHZV-B1w-iwRe.js +10 -0
- package/dist/assets/channel-BEHOSFc5.js +1 -0
- package/dist/assets/{channels-list-page-CvCTJraa.js → channels-list-page-R7M6pzp6.js} +1 -1
- package/dist/assets/{chat-page-B42UUIFR.js → chat-page-152YuwfU.js} +1 -1
- package/dist/assets/chunk-2Q5K7J3B-DrIhesSX.js +1 -0
- package/dist/assets/chunk-32BRIVSS-kG3lg0bC.js +1 -0
- package/dist/assets/chunk-52WLFC77-BLeB7iGk.js +10 -0
- package/dist/assets/chunk-5FCAYU7R-BQga1Rr7.js +1 -0
- package/dist/assets/chunk-5HE753X5-DU81hkcF.js +1 -0
- package/dist/assets/chunk-5JV3BV7I-C2bAx0m7.js +1 -0
- package/dist/assets/chunk-5TONJI2A-BExIIgWY.js +2 -0
- package/dist/assets/chunk-5VM5RSS4-C3XB05yh.js +15 -0
- package/dist/assets/chunk-7BUUIJ7U-JiyRtrGu.js +1 -0
- package/dist/assets/chunk-BIQX33UG-BZRV20pI.js +1 -0
- package/dist/assets/chunk-C7G6YPKG-AsyDSQ9j.js +1 -0
- package/dist/assets/chunk-CQNSW5MT-iN-fiXVA.js +1 -0
- package/dist/assets/chunk-CYSBUYHQ-DhC_TRzI.js +1 -0
- package/dist/assets/chunk-EMLP6XTP-QFLK8R6d.js +1 -0
- package/dist/assets/chunk-EX3LRPZG-DzUwhkCz.js +231 -0
- package/dist/assets/chunk-FWX5IMBZ-DFelpZBy.js +2 -0
- package/dist/assets/chunk-HOUHSVGY-BMPwFEwN.js +1 -0
- package/dist/assets/chunk-ICXQ74PX-DH8NJMok.js +2 -0
- package/dist/assets/chunk-JG7HCLWE-D-95AsO4.js +2 -0
- package/dist/assets/chunk-JWPE2WC7-DIaTv8kx.js +1 -0
- package/dist/assets/chunk-KEIR6QF5-A3jEqwzn.js +161 -0
- package/dist/assets/chunk-MOJQB5TN-BPFLzWgj.js +88 -0
- package/dist/assets/chunk-MOZMSUNE-DR_fzxG0.js +1 -0
- package/dist/assets/chunk-OGEWGWER-TIcEoPPH.js +1 -0
- package/dist/assets/chunk-OSBZ3O6U-BALNvSfG.js +1 -0
- package/dist/assets/chunk-PUDLZKDR-I-EXhf_k.js +156 -0
- package/dist/assets/chunk-Q4XR5HBZ-uvIGstBS.js +70 -0
- package/dist/assets/chunk-QBLGF6JB-r-TjLdxa.js +1 -0
- package/dist/assets/chunk-R7FJI6CG-N-1LDgvy.js +1 -0
- package/dist/assets/chunk-RYQCIY6F-jxNASx65.js +1 -0
- package/dist/assets/chunk-U6XO7XAA-Cphbuc7q.js +2 -0
- package/dist/assets/chunk-V7JOEXUC-BLEuBf1s.js +206 -0
- package/dist/assets/chunk-VAUOI2AC-Dpcz6BhT.js +1 -0
- package/dist/assets/chunk-VR4S4FIN-BAUbR0ke.js +1 -0
- package/dist/assets/chunk-WYO6CB5R-Do6SJrnY.js +127 -0
- package/dist/assets/chunk-XXDRQBXY-C2QjjwYX.js +1 -0
- package/dist/assets/chunk-Y2CYZVJY-BGrd8tLy.js +1 -0
- package/dist/assets/chunk-YOTPTUD7-CQqvMTCr.js +1 -0
- package/dist/assets/chunk-ZGVPDNZ5-B7kWWaXv.js +62 -0
- package/dist/assets/chunk-ZIRB5QZD-DTU0cDNh.js +32 -0
- package/dist/assets/classDiagram-OUVF2IWQ-DESMaY3_.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-DwOlByYH.js +1 -0
- package/dist/assets/{config-split-page-DBgt9S8b.js → config-split-page-BlfvfmTm.js} +1 -1
- package/dist/assets/{confirm-dialog-GSXIvoRU.js → confirm-dialog-Dt8Kdbgp.js} +1 -1
- package/dist/assets/cose-bilkent-JH36ORCC-B9LrtV-q.js +1 -0
- package/dist/assets/cynefin-VYW2F7L2-CzjeeOq9.js +1 -0
- package/dist/assets/cynefinDiagram-TSTJHNR4-BfjvW4su.js +62 -0
- package/dist/assets/cytoscape.esm-CRW8q92n.js +321 -0
- package/dist/assets/dagre-DkiXZKkL.js +1 -0
- package/dist/assets/dagre-VKFMJZFB-B1pQKQSY.js +4 -0
- package/dist/assets/defaultLocale-Cdv9x6q7.js +1 -0
- package/dist/assets/{desktop-update-config-7bmNeWIC.js → desktop-update-config-DreMJu9z.js} +1 -1
- package/dist/assets/diagram-FQU43EPY-cB4EZdaP.js +3 -0
- package/dist/assets/diagram-G47NLZAW-CtW8im1B.js +24 -0
- package/dist/assets/diagram-NH7WQ7WH-BDCtrCCm.js +24 -0
- package/dist/assets/diagram-OA4YK3LP-DEMJ42Gt.js +30 -0
- package/dist/assets/diagram-WEI45ONY-CdCcxSYU.js +41 -0
- package/dist/assets/{dist-DC7f4TJH.js → dist-D5ycbwCo.js} +1 -1
- package/dist/assets/dist-dw-gAfM_.js +1 -0
- package/dist/assets/{doc-browser-D0monHjG.js → doc-browser-C9u7N9vH.js} +1 -1
- package/dist/assets/doc-browser-DJQ5XPsi2.js +1 -0
- package/dist/assets/{doc-browser-context-CGwEOhBy.js → doc-browser-context-CCdW9TJf.js} +1 -1
- package/dist/assets/{docx-preview-eFH9DRsS.js → docx-preview-zis3U0Fa.js} +1 -1
- package/dist/assets/{download-DiP9zx-J.js → download-CyPgglKr.js} +1 -1
- package/dist/assets/ebnfDiagram-CCIWWBDH-DBZETBwE.js +1 -0
- package/dist/assets/erDiagram-Q63AITRT-y2zDXprP.js +85 -0
- package/dist/assets/eventmodeling-45OFAUF4-C38BqG8w.js +1 -0
- package/dist/assets/{external-link-C6ZeSPef.js → external-link-BahW1sl3.js} +1 -1
- package/dist/assets/{eye-suvKmtwn.js → eye-D8gGXMkD.js} +1 -1
- package/dist/assets/flowDiagram-23GEKE2U-BoKk8RRq.js +1 -0
- package/dist/assets/{folder-CMELbQGG.js → folder-DGWqFDvE.js} +1 -1
- package/dist/assets/{form-actions-CUAzpNe_.js → form-actions-D2imZLnU.js} +1 -1
- package/dist/assets/ganttDiagram-NO4QXBWP-D2DP344e.js +292 -0
- package/dist/assets/gitGraph-TEB2WS4Q-IsQHHJuS.js +1 -0
- package/dist/assets/gitGraphDiagram-IHSO6WYX-D37uiwA2.js +106 -0
- package/dist/assets/graphlib-BcNFQr5y.js +1 -0
- package/dist/assets/index-0av6WO9-.css +1 -0
- package/dist/assets/index-CT0iYlxV.js +2 -0
- package/dist/assets/info-DKCQHKI2-ofy2qlHI.js +1 -0
- package/dist/assets/infoDiagram-FWYZ7A6U-CG-WAIRi.js +2 -0
- package/dist/assets/init-D8TjIqfm.js +1 -0
- package/dist/assets/ishikawaDiagram-FXEZZL3T-WeCTnW0f.js +70 -0
- package/dist/assets/journeyDiagram-5HDEW3XC-DUFBW9Td.js +139 -0
- package/dist/assets/kanban-definition-HUTT4EX6-B0lxgMpg.js +89 -0
- package/dist/assets/katex-wEmrEFTg.js +257 -0
- package/dist/assets/line-B78frP_c.js +1 -0
- package/dist/assets/linear-C6lVEcb2.js +1 -0
- package/dist/assets/loader-circle-DtKek-qG.js +1 -0
- package/dist/assets/{logo-badge-Cu5UGH_4.js → logo-badge-CuPetu-v.js} +1 -1
- package/dist/assets/map-Bdri5UL5.js +1 -0
- package/dist/assets/mcp-marketplace-page-4qMwFDpz.js +1 -0
- package/dist/assets/{mcp-marketplace-page-BUzHDwW6.js → mcp-marketplace-page-BbxN5aZF.js} +1 -1
- package/dist/assets/mermaid-parser.core-Cue18vLo.js +4 -0
- package/dist/assets/mermaid.core-CXwWRh5i.js +11 -0
- package/dist/assets/mindmap-definition-LN4V7U3C-CFxz0P0-.js +96 -0
- package/dist/assets/{model-config-page-CWP6pyBm.js → model-config-page-DiJcvBML.js} +1 -1
- package/dist/assets/ordinal-Cbd8t4LB.js +1 -0
- package/dist/assets/packet-7NZHBO7P-Rfopfa1o.js +1 -0
- package/dist/assets/path-DzBnMI1r.js +1 -0
- package/dist/assets/pegDiagram-2B236MQR-B_Qt9zyT.js +1 -0
- package/dist/assets/pie-RZYD4A2V-CJR1xKEv.js +1 -0
- package/dist/assets/pieDiagram-ENE6RG2P-CRQdSuwS.js +39 -0
- package/dist/assets/plus-BwgE-Zwf.js +1 -0
- package/dist/assets/{popover-DImguRok.js → popover-Btp7KVc3.js} +1 -1
- package/dist/assets/preload-helper-D4M6sveU.js +1 -0
- package/dist/assets/{provider-scoped-model-input-CE7p4SbJ.js → provider-scoped-model-input-DZMtoAJG.js} +1 -1
- package/dist/assets/{providers-config-page-BKPo8SjH.js → providers-config-page-DfiWveEF.js} +1 -1
- package/dist/assets/quadrantDiagram-ABIIQ3AL-D5kPpttq.js +7 -0
- package/dist/assets/radar-I7S5WNFK-CDg8Z-1r.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-BHnNmjxO.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-DGtNcusW.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-BRFtsQmm.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-Bj5IypCA.js +1 -0
- package/dist/assets/railroadDiagram-RFXS5EU6-DGh_TGlQ.js +1 -0
- package/dist/assets/{react-5sjAT_6d.js → react-BY-U3h3t.js} +1 -1
- package/dist/assets/{refresh-cw-CHLBzWWj.js → refresh-cw-Cme5qFej.js} +1 -1
- package/dist/assets/remote-BaVECEZw.js +1 -0
- package/dist/assets/requirementDiagram-TGXJPOKE-EmFph0H_.js +84 -0
- package/dist/assets/rotate-cw-CMRZxIkH.js +1 -0
- package/dist/assets/rough.esm-wJ1d3nQl.js +1 -0
- package/dist/assets/{runtime-config-page-1Axv4QGu.js → runtime-config-page-wygwvMB4.js} +1 -1
- package/dist/assets/sankeyDiagram-HTMAVEWB-BXWB5Ugi.js +40 -0
- package/dist/assets/{save-BABzyrjB.js → save-DNg2yJTS.js} +1 -1
- package/dist/assets/{search-BTqxG3ZG.js → search-3ykfrAFt.js} +1 -1
- package/dist/assets/{search-config-page-BkKKmxmS.js → search-config-page-DrVKa_Ls.js} +1 -1
- package/dist/assets/{secrets-config-page-CWJMyu-k.js → secrets-config-page-B39uQ5kF.js} +1 -1
- package/dist/assets/security-config-BPzet76z.js +1 -0
- package/dist/assets/{select-TYZDBNmq.js → select-B5EecXJt.js} +1 -1
- package/dist/assets/sequenceDiagram-DBY2YBRQ-ClKnO7v0.js +162 -0
- package/dist/assets/{setting-row-DR23Z_5I.js → setting-row-Qv1Ps79v.js} +1 -1
- package/dist/assets/{settings-2-D8WWcBnw.js → settings-2-D-3um9Az.js} +1 -1
- package/dist/assets/sizeCapture-X5ZJPWSS-DSo-t5ou.js +1 -0
- package/dist/assets/{skeleton-CloHeg0S.js → skeleton-BgkzQd4U.js} +1 -1
- package/dist/assets/src-Dad2ZbCt.js +1 -0
- package/dist/assets/stateDiagram-2N3HPSRC-BvAalBfz.js +1 -0
- package/dist/assets/stateDiagram-v2-6OUMAXLB-CfMU38yc.js +1 -0
- package/dist/assets/swimlanes-5IMT3BWC-DdVqVa1a.js +2 -0
- package/dist/assets/swimlanesDiagram-G3AALYLV-D9Zb9X57.js +8 -0
- package/dist/assets/{tabs-CX-ckWoo.js → tabs-BVD8gp3y.js} +1 -1
- package/dist/assets/{tag-chip-mCc23Rhb.js → tag-chip-0qn-f3Bo.js} +1 -1
- package/dist/assets/timeline-definition-FHXFAJF6-D4ar8IQY.js +120 -0
- package/dist/assets/{trash-2-SAW1Z4Po.js → trash-2-cnsMppRC.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-Uy7M0WvH.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-BJfGV7KX.js +1 -0
- package/dist/assets/{use-config-BucdaK23.js → use-config-D6yx0lb0.js} +1 -1
- package/dist/assets/{use-confirm-dialog-C95F6sT1.js → use-confirm-dialog-C_o0eQeH.js} +1 -1
- package/dist/assets/{use-viewport-layout-C6m3Nte7.js → use-viewport-layout-BWav4KCL.js} +1 -1
- package/dist/assets/vennDiagram-L72KCM5P-CDXJ_i3p.js +34 -0
- package/dist/assets/wardley-OPB4EBWU-q263iF3K.js +1 -0
- package/dist/assets/wardleyDiagram-EHGQE667-D-dSuT_7.js +78 -0
- package/dist/assets/x-B3o1dWR5.js +1 -0
- package/dist/assets/xychartDiagram-FW5EYKEG-C9JCzsZF.js +7 -0
- package/dist/index.html +33 -32
- package/package.json +5 -5
- package/src/features/chat/components/chat-popover-content.tsx +1 -26
- package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +1 -0
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +28 -11
- package/src/features/chat/features/input/input-surface-plugins/__tests__/slash-command-plugin.test.ts +43 -0
- package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +14 -10
- package/src/features/chat/features/input/utils/__tests__/chat-input-bar.utils.test.ts +51 -0
- package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +61 -21
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +42 -10
- package/src/features/chat/features/message/components/chat-inline-file-preview.tsx +80 -0
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +55 -60
- package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +2 -0
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +22 -24
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +2 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +6 -17
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +41 -19
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +5 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +5 -1
- package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +104 -3
- package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +83 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +4 -1
- package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +96 -25
- package/src/features/chat/managers/__tests__/chat-thread-workspace.manager.test.ts +25 -0
- package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +5 -1
- package/src/features/chat/managers/chat-session-list.manager.ts +1 -0
- package/src/features/chat/managers/chat-thread.manager.ts +15 -37
- package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +9 -0
- package/src/features/chat/stores/chat-thread.store.ts +16 -36
- package/src/features/chat/types/chat-input-bar.types.ts +2 -0
- package/src/shared/components/common/__tests__/brand-header.test.tsx +17 -7
- package/src/shared/components/common/brand-header.tsx +34 -34
- package/src/shared/hooks/use-server-path-read.ts +10 -5
- package/src/shared/lib/api/types.ts +3 -3
- package/src/shared/lib/api/utils/server-path.utils.ts +1 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +8 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +8 -0
- package/src/shared/lib/session-project/__tests__/workspace-file-breadcrumb.test.ts +1 -4
- package/src/shared/lib/session-project/workspace-file-breadcrumb.utils.ts +1 -18
- package/dist/assets/app-presenter-provider-CkHLbvZQ.js +0 -106
- package/dist/assets/doc-browser-CgdoLUT92.js +0 -1
- package/dist/assets/index-BFeNDQ4R.css +0 -1
- package/dist/assets/index-D_6U-M94.js +0 -2
- package/dist/assets/loader-circle-tYHStefV.js +0 -1
- package/dist/assets/mcp-marketplace-page-ohUAdfqJ.js +0 -1
- package/dist/assets/plus-tywizkeY.js +0 -1
- package/dist/assets/remote-DXJryUxB.js +0 -1
- package/dist/assets/rotate-cw-BefO5brU.js +0 -1
- package/dist/assets/security-config-DeQUIXfi.js +0 -1
- package/dist/assets/x-DtCPHwCu.js +0 -1
- package/src/features/chat/components/__tests__/chat-popover-content.test.tsx +0 -41
- package/src/features/chat/components/layout/__tests__/chat-sidebar-utility-menu.test.tsx +0 -55
- /package/dist/assets/{config-hints-fDrYfl0l.js → config-hints-LxG80Uj5.js} +0 -0
- /package/dist/assets/{host-capabilities-zZvY9U63.js → host-capabilities-CFbAfrrA.js} +0 -0
- /package/dist/assets/{jszip.min-Das2IAnb.js → jszip.min-CP5uPNQa.js} +0 -0
- /package/dist/assets/{middleware-BLMHv9YF.js → middleware-CAXxl-af.js} +0 -0
- /package/dist/assets/{provider-models-C_yOh6DE.js → provider-models-BoUhFo9R.js} +0 -0
- /package/dist/assets/{xlsx-B6zVt1RK.js → xlsx-DUqJhg5u.js} +0 -0
package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx
CHANGED
|
@@ -19,6 +19,7 @@ const captures = vi.hoisted(() => ({
|
|
|
19
19
|
openFilePreview: vi.fn(),
|
|
20
20
|
handleToolAction: vi.fn(),
|
|
21
21
|
showContent: vi.fn(),
|
|
22
|
+
filePreviewProps: [] as Array<{ showBreadcrumbs?: boolean }>,
|
|
22
23
|
}));
|
|
23
24
|
|
|
24
25
|
vi.mock("@nextclaw/agent-chat-ui", async (importOriginal) => {
|
|
@@ -61,12 +62,25 @@ vi.mock("@/shared/lib/i18n", () => ({
|
|
|
61
62
|
t: (key: string) => key,
|
|
62
63
|
}));
|
|
63
64
|
|
|
65
|
+
vi.mock(
|
|
66
|
+
"@/features/chat/features/workspace/components/chat-session-workspace-file-preview",
|
|
67
|
+
() => ({
|
|
68
|
+
ChatSessionWorkspaceFilePreview: (props: {
|
|
69
|
+
showBreadcrumbs?: boolean;
|
|
70
|
+
}) => {
|
|
71
|
+
captures.filePreviewProps.push(props);
|
|
72
|
+
return <div data-testid="inline-workspace-file-preview" />;
|
|
73
|
+
},
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
|
|
64
77
|
beforeEach(() => {
|
|
65
78
|
captures.renders = [];
|
|
66
79
|
captures.language = "en";
|
|
67
80
|
captures.openFilePreview.mockReset();
|
|
68
81
|
captures.handleToolAction.mockReset();
|
|
69
82
|
captures.showContent.mockReset();
|
|
83
|
+
captures.filePreviewProps = [];
|
|
70
84
|
});
|
|
71
85
|
|
|
72
86
|
it("reuses adapted message references when the source message object is unchanged", () => {
|
|
@@ -484,22 +498,40 @@ it("passes the inline panel app renderer to the shared chat UI", () => {
|
|
|
484
498
|
expect(captures.renders[captures.renders.length - 1]?.renderPanelAppCard).toEqual(expect.any(Function));
|
|
485
499
|
});
|
|
486
500
|
|
|
487
|
-
it("
|
|
501
|
+
it("renders inline file displays through the workspace file preview", () => {
|
|
488
502
|
render(<ChatMessageListContainer messages={[]} isSending={false} />);
|
|
489
503
|
|
|
490
504
|
const renderInlineDisplay =
|
|
491
505
|
captures.renders[captures.renders.length - 1]?.renderInlineDisplay;
|
|
492
506
|
|
|
493
507
|
expect(renderInlineDisplay).toEqual(expect.any(Function));
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
508
|
+
const rendered = renderInlineDisplay?.({
|
|
509
|
+
target: {
|
|
510
|
+
type: "file",
|
|
511
|
+
payload: { path: "preview.html", viewer: "rendered" },
|
|
512
|
+
},
|
|
513
|
+
title: "Preview",
|
|
514
|
+
description: "Rendered HTML",
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
if (!isValidElement<{ display?: unknown }>(rendered)) {
|
|
518
|
+
throw new Error("Expected inline file renderer to return a React element");
|
|
519
|
+
}
|
|
520
|
+
expect(rendered.props.display).toEqual({
|
|
521
|
+
target: {
|
|
522
|
+
type: "file",
|
|
523
|
+
payload: { path: "preview.html", viewer: "rendered" },
|
|
524
|
+
},
|
|
525
|
+
title: "Preview",
|
|
526
|
+
description: "Rendered HTML",
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
render(rendered);
|
|
530
|
+
|
|
531
|
+
expect(screen.getByText("Preview")).toBeTruthy();
|
|
532
|
+
expect(screen.getByText("preview.html")).toBeTruthy();
|
|
533
|
+
expect(screen.queryByText("Rendered HTML")).toBeNull();
|
|
534
|
+
expect(captures.filePreviewProps.at(-1)?.showBreadcrumbs).toBe(false);
|
|
503
535
|
});
|
|
504
536
|
|
|
505
537
|
it("keeps inline panel app displays expandable from the card header", () => {
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ChatFileOpenActionViewModel,
|
|
3
|
+
ChatInlineDisplayViewModel,
|
|
4
|
+
} from "@nextclaw/agent-chat-ui";
|
|
5
|
+
import { FileText } from "lucide-react";
|
|
6
|
+
import { ChatSessionWorkspaceFilePreview } from "@/features/chat/features/workspace/components/chat-session-workspace-file-preview";
|
|
7
|
+
import { createWorkspaceFileTab } from "@/features/chat/features/workspace/utils/chat-workspace-file-tab.utils";
|
|
8
|
+
|
|
9
|
+
type ChatInlineFilePreviewProps = {
|
|
10
|
+
display: ChatInlineDisplayViewModel;
|
|
11
|
+
parentSessionKey: string | null;
|
|
12
|
+
sessionProjectRoot: string | null;
|
|
13
|
+
sessionWorkingDir: string | null;
|
|
14
|
+
onFileOpen: (action: ChatFileOpenActionViewModel) => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function readFileName(path: string): string {
|
|
18
|
+
return path.split(/[\\/]/).filter(Boolean).pop() ?? path;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function ChatInlineFilePreview({
|
|
22
|
+
display,
|
|
23
|
+
parentSessionKey,
|
|
24
|
+
sessionProjectRoot,
|
|
25
|
+
sessionWorkingDir,
|
|
26
|
+
onFileOpen,
|
|
27
|
+
}: ChatInlineFilePreviewProps) {
|
|
28
|
+
if (display.target.type !== "file") {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const { path, line, column, viewer } = display.target.payload;
|
|
32
|
+
const file = createWorkspaceFileTab(
|
|
33
|
+
{
|
|
34
|
+
path,
|
|
35
|
+
label: display.title,
|
|
36
|
+
viewMode: "preview",
|
|
37
|
+
previewViewer: viewer,
|
|
38
|
+
line,
|
|
39
|
+
column,
|
|
40
|
+
},
|
|
41
|
+
parentSessionKey,
|
|
42
|
+
);
|
|
43
|
+
if (!file) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const title = display.title ?? readFileName(file.path);
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<section
|
|
50
|
+
className="my-2 w-full max-w-[48rem] overflow-hidden rounded-lg border border-border bg-card shadow-sm"
|
|
51
|
+
data-chat-inline-file-preview="true"
|
|
52
|
+
data-chat-message-wide-content="true"
|
|
53
|
+
>
|
|
54
|
+
<header className="border-b border-border bg-muted/45 px-3 py-2">
|
|
55
|
+
<div className="flex min-w-0 items-center gap-2 text-xs font-medium text-foreground">
|
|
56
|
+
<FileText
|
|
57
|
+
className="h-3.5 w-3.5 shrink-0 text-muted-foreground"
|
|
58
|
+
aria-hidden
|
|
59
|
+
/>
|
|
60
|
+
<span className="truncate">{title}</span>
|
|
61
|
+
</div>
|
|
62
|
+
<p
|
|
63
|
+
className="mt-1 truncate font-mono text-[11px] font-normal text-muted-foreground"
|
|
64
|
+
title={file.path}
|
|
65
|
+
>
|
|
66
|
+
{file.path}
|
|
67
|
+
</p>
|
|
68
|
+
</header>
|
|
69
|
+
<div className="h-[420px] min-h-[240px] max-h-[min(60vh,420px)] overflow-hidden">
|
|
70
|
+
<ChatSessionWorkspaceFilePreview
|
|
71
|
+
file={file}
|
|
72
|
+
sessionProjectRoot={sessionProjectRoot}
|
|
73
|
+
sessionWorkingDir={sessionWorkingDir}
|
|
74
|
+
showBreadcrumbs={false}
|
|
75
|
+
onFileOpen={onFileOpen}
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
78
|
+
</section>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -4,13 +4,11 @@ import {
|
|
|
4
4
|
type ChatInlineDisplayViewModel,
|
|
5
5
|
type ChatInlineTokenViewModel,
|
|
6
6
|
type ChatMessageViewModel,
|
|
7
|
+
type ChatPanelAppCardViewModel,
|
|
7
8
|
ChatMessageList,
|
|
8
9
|
} from "@nextclaw/agent-chat-ui";
|
|
9
10
|
import { usePresenter } from "@/features/chat/components/providers/chat-presenter.provider";
|
|
10
|
-
import {
|
|
11
|
-
adaptChatMessage,
|
|
12
|
-
type ChatMessageSource,
|
|
13
|
-
} from "@/features/chat/features/message/utils/chat-message.utils";
|
|
11
|
+
import { adaptChatMessage, type ChatMessageSource } from "@/features/chat/features/message/utils/chat-message.utils";
|
|
14
12
|
import { buildChatMessageProcessSummary } from "@/features/chat/features/message/utils/chat-message-process-summary.utils";
|
|
15
13
|
import {
|
|
16
14
|
buildChatMessageAdapterTexts,
|
|
@@ -23,6 +21,7 @@ import {
|
|
|
23
21
|
type ContextCompactionTimelineView,
|
|
24
22
|
} from "@/features/chat/features/session/utils/ncp-session-context-metadata.utils";
|
|
25
23
|
import { AgentIdentityAvatar } from "@/shared/components/common/agent-identity";
|
|
24
|
+
import { ChatInlineFilePreview } from "@/features/chat/features/message/components/chat-inline-file-preview";
|
|
26
25
|
import { ChatInlinePanelAppCard } from "@/features/chat/features/message/components/chat-inline-panel-app-card";
|
|
27
26
|
import { useChatQueryStore } from "@/features/chat/stores/ncp-chat-query.store";
|
|
28
27
|
import { useChatSessionListStore } from "@/features/chat/stores/chat-session-list.store";
|
|
@@ -62,6 +61,10 @@ function renderChatInlineDisplay(display: ChatInlineDisplayViewModel) {
|
|
|
62
61
|
/>
|
|
63
62
|
);
|
|
64
63
|
}
|
|
64
|
+
|
|
65
|
+
const renderChatToolAgent = (agentId: string) => <AgentIdentityAvatar agentId={agentId} className="h-4 w-4 shrink-0" />;
|
|
66
|
+
const renderChatPanelAppCard = (panelApp: ChatPanelAppCardViewModel) => <ChatInlinePanelAppCard panelApp={panelApp} />;
|
|
67
|
+
|
|
65
68
|
type ContextInheritanceTimelineView = {
|
|
66
69
|
sourceSessionId: string;
|
|
67
70
|
inheritedMessageCount: number;
|
|
@@ -88,11 +91,7 @@ type ChatTimelineItem =
|
|
|
88
91
|
inheritance: ContextInheritanceTimelineView;
|
|
89
92
|
};
|
|
90
93
|
|
|
91
|
-
function ChatContextCompactionDivider({
|
|
92
|
-
checkpoint,
|
|
93
|
-
}: {
|
|
94
|
-
checkpoint: ContextCompactionTimelineView;
|
|
95
|
-
}) {
|
|
94
|
+
function ChatContextCompactionDivider({ checkpoint }: { checkpoint: ContextCompactionTimelineView }) {
|
|
96
95
|
const title = [
|
|
97
96
|
`${t("chatContextCompactionCoveredMessages")}: ${checkpoint.coveredSessionMessageCount}`,
|
|
98
97
|
`${t("chatContextCompactionOriginalTokens")}: ${checkpoint.originalEstimatedTokens}`,
|
|
@@ -118,11 +117,7 @@ function ChatContextCompactionDivider({
|
|
|
118
117
|
);
|
|
119
118
|
}
|
|
120
119
|
|
|
121
|
-
function ChatContextInheritanceDivider({
|
|
122
|
-
inheritance,
|
|
123
|
-
}: {
|
|
124
|
-
inheritance: ContextInheritanceTimelineView;
|
|
125
|
-
}) {
|
|
120
|
+
function ChatContextInheritanceDivider({ inheritance }: { inheritance: ContextInheritanceTimelineView }) {
|
|
126
121
|
const title = [
|
|
127
122
|
`${t("chatContextInheritanceSourceSession")}: ${inheritance.sourceSessionId}`,
|
|
128
123
|
`${t("chatContextInheritanceMessages")}: ${inheritance.inheritedMessageCount}`,
|
|
@@ -144,20 +139,12 @@ function resolveCompactionBoundaryIndex(params: {
|
|
|
144
139
|
visibleRawMessages: readonly NcpMessage[];
|
|
145
140
|
rawMessageId: string;
|
|
146
141
|
}): number {
|
|
147
|
-
const {
|
|
148
|
-
|
|
149
|
-
rawMessages,
|
|
150
|
-
visibleRawMessages,
|
|
151
|
-
} = params;
|
|
152
|
-
const physicalIndex = rawMessages.findIndex(
|
|
153
|
-
(message) => message.id === rawMessageId,
|
|
154
|
-
);
|
|
142
|
+
const { rawMessageId, rawMessages, visibleRawMessages } = params;
|
|
143
|
+
const physicalIndex = rawMessages.findIndex((message) => message.id === rawMessageId);
|
|
155
144
|
if (physicalIndex < 0) {
|
|
156
145
|
return visibleRawMessages.length - 1;
|
|
157
146
|
}
|
|
158
|
-
const previousVisibleCount = rawMessages
|
|
159
|
-
.slice(0, physicalIndex)
|
|
160
|
-
.filter(isVisibleChatMessage).length;
|
|
147
|
+
const previousVisibleCount = rawMessages.slice(0, physicalIndex).filter(isVisibleChatMessage).length;
|
|
161
148
|
return previousVisibleCount - 1;
|
|
162
149
|
}
|
|
163
150
|
|
|
@@ -170,9 +157,7 @@ function isVisibleChatMessage(message: NcpMessage): boolean {
|
|
|
170
157
|
return !readContextCompactionTimeline(message) && !readInheritedSourceSessionId(message);
|
|
171
158
|
}
|
|
172
159
|
|
|
173
|
-
function resolveContextInheritanceBoundary(
|
|
174
|
-
messages: readonly NcpMessage[],
|
|
175
|
-
): ContextInheritanceTimelineBoundary | null {
|
|
160
|
+
function resolveContextInheritanceBoundary(messages: readonly NcpMessage[]): ContextInheritanceTimelineBoundary | null {
|
|
176
161
|
const boundaryIndex = messages.findIndex((message) => readInheritedSourceSessionId(message));
|
|
177
162
|
if (boundaryIndex < 0) {
|
|
178
163
|
return null;
|
|
@@ -184,7 +169,8 @@ function resolveContextInheritanceBoundary(
|
|
|
184
169
|
return {
|
|
185
170
|
boundaryIndex: messages.slice(0, boundaryIndex).filter(isVisibleChatMessage).length,
|
|
186
171
|
sourceSessionId,
|
|
187
|
-
inheritedMessageCount: messages.filter((message) => readInheritedSourceSessionId(message) === sourceSessionId)
|
|
172
|
+
inheritedMessageCount: messages.filter((message) => readInheritedSourceSessionId(message) === sourceSessionId)
|
|
173
|
+
.length,
|
|
188
174
|
};
|
|
189
175
|
}
|
|
190
176
|
|
|
@@ -199,8 +185,12 @@ function buildTimelineItems(params: {
|
|
|
199
185
|
checkpoint: readContextCompactionTimeline(message),
|
|
200
186
|
}))
|
|
201
187
|
.filter(
|
|
202
|
-
(
|
|
203
|
-
|
|
188
|
+
(
|
|
189
|
+
entry,
|
|
190
|
+
): entry is {
|
|
191
|
+
rawMessageId: string;
|
|
192
|
+
checkpoint: ContextCompactionTimelineView;
|
|
193
|
+
} => Boolean(entry.checkpoint),
|
|
204
194
|
)
|
|
205
195
|
.map((entry) => ({
|
|
206
196
|
key: entry.rawMessageId,
|
|
@@ -290,19 +280,35 @@ export function ChatMessageListContainer({
|
|
|
290
280
|
const presenter = usePresenter();
|
|
291
281
|
const { language } = useI18n();
|
|
292
282
|
const messageLayout = useChatMessageLayoutStore((state) => state.layout);
|
|
293
|
-
const selectedSessionKey = useChatSessionListStore(
|
|
294
|
-
(state) => state.snapshot.selectedSessionKey,
|
|
295
|
-
);
|
|
283
|
+
const selectedSessionKey = useChatSessionListStore((state) => state.snapshot.selectedSessionKey);
|
|
296
284
|
const selectedSession = useNcpChatSelectedSession(selectedSessionKey);
|
|
297
285
|
const localFileBasePath = selectedSession?.workingDir ?? selectedSession?.projectRoot ?? null;
|
|
286
|
+
const renderInlineDisplayWithFiles = useCallback(
|
|
287
|
+
(display: ChatInlineDisplayViewModel) => {
|
|
288
|
+
const panelAppDisplay = renderChatInlineDisplay(display);
|
|
289
|
+
if (panelAppDisplay) {
|
|
290
|
+
return panelAppDisplay;
|
|
291
|
+
}
|
|
292
|
+
if (display.target.type === "file") {
|
|
293
|
+
return (
|
|
294
|
+
<ChatInlineFilePreview
|
|
295
|
+
display={display}
|
|
296
|
+
parentSessionKey={selectedSessionKey}
|
|
297
|
+
sessionProjectRoot={selectedSession?.projectRoot ?? null}
|
|
298
|
+
sessionWorkingDir={localFileBasePath}
|
|
299
|
+
onFileOpen={presenter.chatThreadManager.openFilePreview}
|
|
300
|
+
/>
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
return undefined;
|
|
304
|
+
},
|
|
305
|
+
[localFileBasePath, presenter.chatThreadManager, selectedSession?.projectRoot, selectedSessionKey],
|
|
306
|
+
);
|
|
298
307
|
const resolveFileContentUrl = useCallback(
|
|
299
308
|
(action: { path: string }) => buildServerPathContentUrl(action.path, localFileBasePath),
|
|
300
309
|
[localFileBasePath],
|
|
301
310
|
);
|
|
302
|
-
const texts = useMemo(
|
|
303
|
-
() => buildChatMessageAdapterTexts(language),
|
|
304
|
-
[language],
|
|
305
|
-
);
|
|
311
|
+
const texts = useMemo(() => buildChatMessageAdapterTexts(language), [language]);
|
|
306
312
|
|
|
307
313
|
const messages = useMemo(() => {
|
|
308
314
|
const visibleRawMessages = rawMessages.filter(isVisibleChatMessage);
|
|
@@ -335,7 +341,11 @@ export function ChatMessageListContainer({
|
|
|
335
341
|
texts,
|
|
336
342
|
});
|
|
337
343
|
|
|
338
|
-
messageViewModelCache.set(message, {
|
|
344
|
+
messageViewModelCache.set(message, {
|
|
345
|
+
language,
|
|
346
|
+
processSummaryLabel,
|
|
347
|
+
viewModel,
|
|
348
|
+
});
|
|
339
349
|
return [viewModel];
|
|
340
350
|
});
|
|
341
351
|
}, [language, rawMessages, texts]);
|
|
@@ -343,20 +353,12 @@ export function ChatMessageListContainer({
|
|
|
343
353
|
const hasAssistantDraft = useMemo(
|
|
344
354
|
() =>
|
|
345
355
|
messages.some(
|
|
346
|
-
(message) =>
|
|
347
|
-
message.role === "assistant" &&
|
|
348
|
-
(message.status === "streaming" || message.status === "pending"),
|
|
356
|
+
(message) => message.role === "assistant" && (message.status === "streaming" || message.status === "pending"),
|
|
349
357
|
),
|
|
350
358
|
[messages],
|
|
351
359
|
);
|
|
352
|
-
const messageTexts = useMemo(
|
|
353
|
-
|
|
354
|
-
[language],
|
|
355
|
-
);
|
|
356
|
-
const timelineItems = useMemo(
|
|
357
|
-
() => buildTimelineItems({ rawMessages, messages }),
|
|
358
|
-
[messages, rawMessages],
|
|
359
|
-
);
|
|
360
|
+
const messageTexts = useMemo(() => buildChatMessageTexts(language), [language]);
|
|
361
|
+
const timelineItems = useMemo(() => buildTimelineItems({ rawMessages, messages }), [messages, rawMessages]);
|
|
360
362
|
const sessionSkillsQuery = useChatQueryStore((state) => state.snapshot.sessionSkillsQuery);
|
|
361
363
|
const handleInlineTokenClick = useCallback(
|
|
362
364
|
(token: ChatInlineTokenViewModel) => {
|
|
@@ -419,16 +421,9 @@ export function ChatMessageListContainer({
|
|
|
419
421
|
onAttachmentOpen={handleAttachmentOpen}
|
|
420
422
|
onInlineTokenClick={handleInlineTokenClick}
|
|
421
423
|
resolveFileContentUrl={resolveFileContentUrl}
|
|
422
|
-
renderInlineDisplay={
|
|
423
|
-
renderToolAgent={
|
|
424
|
-
|
|
425
|
-
agentId={agentId}
|
|
426
|
-
className="h-4 w-4 shrink-0"
|
|
427
|
-
/>
|
|
428
|
-
)}
|
|
429
|
-
renderPanelAppCard={(panelApp) => (
|
|
430
|
-
<ChatInlinePanelAppCard panelApp={panelApp} />
|
|
431
|
-
)}
|
|
424
|
+
renderInlineDisplay={renderInlineDisplayWithFiles}
|
|
425
|
+
renderToolAgent={renderChatToolAgent}
|
|
426
|
+
renderPanelAppCard={renderChatPanelAppCard}
|
|
432
427
|
/>
|
|
433
428
|
),
|
|
434
429
|
)}
|
|
@@ -106,6 +106,8 @@ export function buildChatMessageTexts(
|
|
|
106
106
|
copiedCodeLabel: t("chatCodeCopied"),
|
|
107
107
|
copyMessageLabel: t("chatMessageCopy"),
|
|
108
108
|
copiedMessageLabel: t("chatMessageCopied"),
|
|
109
|
+
mermaidDiagramLabel: t("chatMermaidDiagram"),
|
|
110
|
+
mermaidRenderErrorLabel: t("chatMermaidRenderError"),
|
|
109
111
|
typingLabel: t("chatTyping"),
|
|
110
112
|
reasoningCharacterCountTemplates: {
|
|
111
113
|
inProgress: t("chatReasoningInProgressCharacterCount"),
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
} from "@nextclaw/agent-chat-ui";
|
|
7
7
|
import { ChatSessionWorkspaceFilePreview } from "@/features/chat/features/workspace/components/chat-session-workspace-file-preview";
|
|
8
8
|
import type { ChatWorkspaceFileTab } from "@/features/chat/stores/chat-thread.store";
|
|
9
|
+
import type { ServerPathReadView } from "@/shared/lib/api";
|
|
9
10
|
import { t } from "@/shared/lib/i18n";
|
|
10
11
|
|
|
11
12
|
const serverPathReadMock = vi.fn();
|
|
@@ -22,15 +23,10 @@ type RenderWorkspaceFilePreviewOptions = {
|
|
|
22
23
|
refreshVersion?: number;
|
|
23
24
|
sessionProjectRoot?: string | null;
|
|
24
25
|
sessionWorkingDir?: string | null;
|
|
26
|
+
showBreadcrumbs?: boolean;
|
|
25
27
|
};
|
|
26
28
|
|
|
27
|
-
type TextReadDataOverrides =
|
|
28
|
-
kind?: "text" | "markdown" | "binary";
|
|
29
|
-
languageHint?: string;
|
|
30
|
-
resolvedPath?: string;
|
|
31
|
-
text?: string;
|
|
32
|
-
truncated?: boolean;
|
|
33
|
-
};
|
|
29
|
+
type TextReadDataOverrides = Partial<ServerPathReadView>;
|
|
34
30
|
|
|
35
31
|
vi.mock("@/shared/hooks/use-server-path-read", () => ({
|
|
36
32
|
useServerPathRead: (...args: unknown[]) => serverPathReadMock(...args),
|
|
@@ -97,6 +93,7 @@ function mockTextRead(overrides: TextReadDataOverrides = {}) {
|
|
|
97
93
|
data: {
|
|
98
94
|
kind: "text",
|
|
99
95
|
resolvedPath: "/tmp/example.ts",
|
|
96
|
+
startLine: 1,
|
|
100
97
|
text: "const answer = 42;\n",
|
|
101
98
|
truncated: false,
|
|
102
99
|
...overrides,
|
|
@@ -110,6 +107,7 @@ function renderWorkspaceFilePreview({
|
|
|
110
107
|
refreshVersion,
|
|
111
108
|
sessionProjectRoot = "/tmp",
|
|
112
109
|
sessionWorkingDir = "/tmp",
|
|
110
|
+
showBreadcrumbs,
|
|
113
111
|
}: RenderWorkspaceFilePreviewOptions = {}) {
|
|
114
112
|
const view = render(
|
|
115
113
|
<ChatSessionWorkspaceFilePreview
|
|
@@ -117,6 +115,7 @@ function renderWorkspaceFilePreview({
|
|
|
117
115
|
sessionProjectRoot={sessionProjectRoot}
|
|
118
116
|
sessionWorkingDir={sessionWorkingDir}
|
|
119
117
|
refreshVersion={refreshVersion}
|
|
118
|
+
showBreadcrumbs={showBreadcrumbs}
|
|
120
119
|
onFileOpen={onFileOpen}
|
|
121
120
|
/>,
|
|
122
121
|
);
|
|
@@ -525,11 +524,16 @@ describe("ChatSessionWorkspaceFilePreview text rendering", () => {
|
|
|
525
524
|
).toBe("workspace");
|
|
526
525
|
});
|
|
527
526
|
|
|
528
|
-
it("passes server language hints
|
|
529
|
-
mockTextRead({
|
|
527
|
+
it("passes server language hints and keeps location out of breadcrumbs", () => {
|
|
528
|
+
mockTextRead({
|
|
529
|
+
languageHint: "js",
|
|
530
|
+
resolvedPath: "/tmp/example.js",
|
|
531
|
+
});
|
|
530
532
|
renderWorkspaceFilePreview({
|
|
531
533
|
file: {
|
|
534
|
+
column: 4,
|
|
532
535
|
label: "example.js",
|
|
536
|
+
line: 12,
|
|
533
537
|
path: "/tmp/example.js",
|
|
534
538
|
viewMode: "preview",
|
|
535
539
|
},
|
|
@@ -540,6 +544,7 @@ describe("ChatSessionWorkspaceFilePreview text rendering", () => {
|
|
|
540
544
|
.getByTestId("file-code-surface")
|
|
541
545
|
.getAttribute("data-language-hint"),
|
|
542
546
|
).toBe("js");
|
|
547
|
+
expect(screen.queryByText("L12:4")).toBeNull();
|
|
543
548
|
});
|
|
544
549
|
|
|
545
550
|
it("renders Markdown by default and keeps source view explicit", () => {
|
|
@@ -761,6 +766,14 @@ describe("ChatSessionWorkspaceFilePreview text rendering", () => {
|
|
|
761
766
|
});
|
|
762
767
|
|
|
763
768
|
describe("ChatSessionWorkspaceFilePreview breadcrumbs", () => {
|
|
769
|
+
it("can hide workspace breadcrumbs for inline placements", () => {
|
|
770
|
+
mockTextRead();
|
|
771
|
+
renderWorkspaceFilePreview({ showBreadcrumbs: false });
|
|
772
|
+
|
|
773
|
+
expect(screen.queryByTestId("workspace-file-breadcrumbs")).toBeNull();
|
|
774
|
+
expect(screen.getByTestId("file-code-surface")).toBeTruthy();
|
|
775
|
+
});
|
|
776
|
+
|
|
764
777
|
it("renders project-relative breadcrumbs when the file is inside the workspace", () => {
|
|
765
778
|
mockTextRead({ resolvedPath: "/tmp/workspace/src/example.ts" });
|
|
766
779
|
renderWorkspaceFilePreview({
|
|
@@ -832,21 +845,6 @@ describe("ChatSessionWorkspaceFilePreview breadcrumbs", () => {
|
|
|
832
845
|
).toContain("h-6");
|
|
833
846
|
});
|
|
834
847
|
|
|
835
|
-
it("keeps line and truncation metadata without the duplicated type badge", () => {
|
|
836
|
-
mockTextRead({ truncated: true });
|
|
837
|
-
renderWorkspaceFilePreview({
|
|
838
|
-
file: {
|
|
839
|
-
viewMode: "preview",
|
|
840
|
-
line: 12,
|
|
841
|
-
column: 4,
|
|
842
|
-
},
|
|
843
|
-
});
|
|
844
|
-
|
|
845
|
-
expect(screen.getByText("L12:4")).toBeTruthy();
|
|
846
|
-
expect(screen.getByText(t("chatWorkspacePreviewTruncated"))).toBeTruthy();
|
|
847
|
-
expect(screen.queryByText(t("chatWorkspacePreview"))).toBeNull();
|
|
848
|
-
});
|
|
849
|
-
|
|
850
848
|
it("uses the session working directory as the base path when no project root is set", () => {
|
|
851
849
|
mockTextRead({
|
|
852
850
|
resolvedPath: "/tmp/agent-workspace/AGENTS.md",
|
|
@@ -9,7 +9,7 @@ const mocks = vi.hoisted(() => ({
|
|
|
9
9
|
syncVisibleWorkspaceSelection: vi.fn(),
|
|
10
10
|
selectChildSessionDetail: vi.fn(),
|
|
11
11
|
selectWorkspaceFile: vi.fn(),
|
|
12
|
-
|
|
12
|
+
closeWorkspaceTab: vi.fn(),
|
|
13
13
|
openSessionCronPanel: vi.fn(),
|
|
14
14
|
goBackWorkspacePanel: vi.fn(),
|
|
15
15
|
goForwardWorkspacePanel: vi.fn(),
|
|
@@ -72,6 +72,7 @@ function renderPanel(displayMode: "docked" | "overlay" = "docked") {
|
|
|
72
72
|
activeSideChatDraft={null}
|
|
73
73
|
workspaceFileTabs={[fileTab]}
|
|
74
74
|
activeWorkspaceFileKey={fileTab.key}
|
|
75
|
+
closedWorkspaceTabEntries={[]}
|
|
75
76
|
workspaceNavigationHistory={[{ kind: "file", key: fileTab.key }]}
|
|
76
77
|
workspaceNavigationHistoryIndex={0}
|
|
77
78
|
activePanelKind="file"
|
package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx
CHANGED
|
@@ -12,15 +12,10 @@ import type {
|
|
|
12
12
|
import { t } from "@/shared/lib/i18n";
|
|
13
13
|
import { cn } from "@/shared/lib/utils";
|
|
14
14
|
|
|
15
|
-
function
|
|
15
|
+
function WorkspaceBreadcrumbWarningChip({ value }: { value: string }) {
|
|
16
16
|
return (
|
|
17
17
|
<span
|
|
18
|
-
className=
|
|
19
|
-
"inline-flex h-5 items-center rounded-sm border px-1.5 text-[10px] font-medium leading-none",
|
|
20
|
-
tone === "warning"
|
|
21
|
-
? "border-amber-200 bg-amber-50 text-amber-700"
|
|
22
|
-
: "border-gray-200 bg-gray-50 text-gray-500",
|
|
23
|
-
)}
|
|
18
|
+
className="inline-flex h-5 items-center rounded-sm border border-amber-200 bg-amber-50 px-1.5 text-[10px] font-medium leading-none text-amber-700"
|
|
24
19
|
>
|
|
25
20
|
{value}
|
|
26
21
|
</span>
|
|
@@ -116,17 +111,11 @@ export function ChatSessionWorkspaceFileBreadcrumbs({
|
|
|
116
111
|
))}
|
|
117
112
|
</div>
|
|
118
113
|
|
|
119
|
-
{breadcrumb.
|
|
114
|
+
{breadcrumb.truncated ? (
|
|
120
115
|
<div className="flex shrink-0 flex-wrap items-center justify-end gap-1">
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
{breadcrumb.truncated ? (
|
|
125
|
-
<WorkspaceBreadcrumbMetaChip
|
|
126
|
-
tone="warning"
|
|
127
|
-
value={t("chatWorkspacePreviewTruncated")}
|
|
128
|
-
/>
|
|
129
|
-
) : null}
|
|
116
|
+
<WorkspaceBreadcrumbWarningChip
|
|
117
|
+
value={t("chatWorkspacePreviewTruncated")}
|
|
118
|
+
/>
|
|
130
119
|
</div>
|
|
131
120
|
) : null}
|
|
132
121
|
</div>
|