@nextclaw/ui 0.15.2 → 0.15.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/dist/assets/aiden0z-pptx-renderer.es-Bd99vut2.js +94 -0
- package/dist/assets/api-BOXOrpcJ.js +13 -0
- package/dist/assets/app-presenter-provider-CkHLbvZQ.js +106 -0
- package/dist/assets/app-presenter-provider-D3BuuOyZ.css +1 -0
- package/dist/assets/appearance-settings-page-fLIJbx1C.js +1 -0
- package/dist/assets/{book-open-Ba2f7YiG.js → book-open-DWUjS6aW.js} +1 -1
- package/dist/assets/channels-list-page-CvCTJraa.js +8 -0
- package/dist/assets/chat-page-B42UUIFR.js +1 -0
- package/dist/assets/chunk-DseTPa7n.js +1 -0
- package/dist/assets/config-split-page-DBgt9S8b.js +1 -0
- package/dist/assets/confirm-dialog-GSXIvoRU.js +5 -0
- package/dist/assets/desktop-update-config-7bmNeWIC.js +1 -0
- package/dist/assets/dist-DC7f4TJH.js +41 -0
- package/dist/assets/doc-browser-CgdoLUT92.js +1 -0
- package/dist/assets/doc-browser-D0monHjG.js +1 -0
- package/dist/assets/doc-browser-context-CGwEOhBy.js +1 -0
- package/dist/assets/docx-preview-eFH9DRsS.js +20 -0
- package/dist/assets/download-DiP9zx-J.js +1 -0
- package/dist/assets/{external-link-DxuPaDoK.js → external-link-C6ZeSPef.js} +1 -1
- package/dist/assets/eye-suvKmtwn.js +1 -0
- package/dist/assets/folder-CMELbQGG.js +1 -0
- package/dist/assets/{form-actions-BztL7P_T.js → form-actions-CUAzpNe_.js} +1 -1
- package/dist/assets/index-BFeNDQ4R.css +1 -0
- package/dist/assets/index-D_6U-M94.js +2 -0
- package/dist/assets/jszip.min-Das2IAnb.js +2 -0
- package/dist/assets/loader-circle-tYHStefV.js +1 -0
- package/dist/assets/logo-badge-Cu5UGH_4.js +1 -0
- package/dist/assets/mcp-marketplace-page-BUzHDwW6.js +9 -0
- package/dist/assets/mcp-marketplace-page-ohUAdfqJ.js +1 -0
- package/dist/assets/model-config-page-CWP6pyBm.js +1 -0
- package/dist/assets/plus-tywizkeY.js +1 -0
- package/dist/assets/popover-DImguRok.js +1 -0
- package/dist/assets/provider-models-C_yOh6DE.js +1 -0
- package/dist/assets/provider-scoped-model-input-CE7p4SbJ.js +1 -0
- package/dist/assets/providers-config-page-BKPo8SjH.js +1 -0
- package/dist/assets/react-5sjAT_6d.js +8 -0
- package/dist/assets/{refresh-cw-eT8BF-8B.js → refresh-cw-CHLBzWWj.js} +1 -1
- package/dist/assets/remote-DXJryUxB.js +1 -0
- package/dist/assets/rotate-cw-BefO5brU.js +1 -0
- package/dist/assets/runtime-config-page-1Axv4QGu.js +1 -0
- package/dist/assets/{save-Cb2g0BOi.js → save-BABzyrjB.js} +1 -1
- package/dist/assets/{search-BcHjwdsb.js → search-BTqxG3ZG.js} +1 -1
- package/dist/assets/search-config-page-BkKKmxmS.js +1 -0
- package/dist/assets/secrets-config-page-CWJMyu-k.js +3 -0
- package/dist/assets/security-config-DeQUIXfi.js +1 -0
- package/dist/assets/select-TYZDBNmq.js +1 -0
- package/dist/assets/setting-row-DR23Z_5I.js +1 -0
- package/dist/assets/{settings-2-2DWauOjY.js → settings-2-D8WWcBnw.js} +1 -1
- package/dist/assets/{skeleton-P5oM14E1.js → skeleton-CloHeg0S.js} +1 -1
- package/dist/assets/tabs-CX-ckWoo.js +1 -0
- package/dist/assets/tag-chip-mCc23Rhb.js +1 -0
- package/dist/assets/trash-2-SAW1Z4Po.js +1 -0
- package/dist/assets/use-config-BucdaK23.js +1 -0
- package/dist/assets/use-confirm-dialog-C95F6sT1.js +1 -0
- package/dist/assets/use-viewport-layout-C6m3Nte7.js +1 -0
- package/dist/assets/x-DtCPHwCu.js +1 -0
- package/dist/assets/xlsx-B6zVt1RK.js +64 -0
- package/dist/index.html +34 -28
- package/package.json +14 -9
- package/src/app/components/layout/sidebar-items.tsx +3 -3
- package/src/app/components/layout/sidebar-rail.styles.ts +2 -2
- package/src/app/components/layout/sidebar.tsx +1 -1
- package/src/app/styles/design-system.css +17 -4
- package/src/features/chat/components/__tests__/chat-popover-content.test.tsx +41 -0
- package/src/features/chat/components/chat-popover-content.tsx +26 -0
- package/src/features/chat/components/conversation/__tests__/chat-conversation-content.test.tsx +13 -0
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +21 -11
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header.test.tsx +2 -2
- package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +28 -1
- package/src/features/chat/components/conversation/chat-conversation-content.tsx +5 -4
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +9 -18
- package/src/features/chat/components/conversation/chat-conversation-track.tsx +35 -0
- package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +1 -0
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +7 -7
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +4 -15
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +20 -1
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +69 -54
- package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +1 -1
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +62 -1
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +63 -2
- package/src/features/chat/features/message/utils/__tests__/chat-message-file-operation.utils.test.ts +30 -0
- package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +11 -1
- package/src/features/chat/features/message/utils/__tests__/chat-message-texts.utils.test.ts +23 -0
- package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +5 -0
- package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +138 -0
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-session-item.test.tsx +37 -0
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +5 -4
- package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +3 -8
- package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +65 -20
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +26 -28
- package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +3 -3
- package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +5 -5
- package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +4 -4
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +4 -4
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +463 -99
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +113 -2
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +1 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +197 -44
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumb-browser.tsx +11 -5
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +8 -6
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +99 -67
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +239 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +56 -6
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +29 -7
- package/src/features/chat/features/workspace/components/file-content-preview/use-workspace-file-buffer.ts +42 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-document-preview-state.tsx +18 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-docx-preview.css +89 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-docx-preview.tsx +87 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-presentation-preview.tsx +82 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-spreadsheet-preview.tsx +180 -0
- package/src/features/chat/features/workspace/components/workspace-file-content-preview.tsx +191 -0
- package/src/features/chat/features/workspace/hooks/use-chat-conversation-workspace-state.ts +1 -4
- package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +53 -10
- package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +68 -2
- package/src/features/chat/features/workspace/utils/chat-workspace-file-tab-persistence.utils.ts +21 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +63 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-file-viewer.utils.ts +49 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-panel-layout.utils.ts +13 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +120 -38
- package/src/features/chat/index.ts +1 -0
- package/src/features/chat/managers/__tests__/chat-thread-workspace.manager.test.ts +76 -0
- package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +44 -60
- package/src/features/chat/managers/chat-thread.manager.ts +123 -124
- package/src/features/chat/pages/ncp-chat-page.tsx +1 -2
- package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +78 -1
- package/src/features/chat/stores/chat-message-layout.store.test.ts +37 -0
- package/src/features/chat/stores/chat-message-layout.store.ts +41 -0
- package/src/features/chat/stores/chat-thread.store.ts +73 -13
- package/src/features/cron/components/cron-config.tsx +63 -80
- package/src/features/marketplace/components/detail-doc/__tests__/marketplace-detail-doc.test.tsx +44 -6
- package/src/features/marketplace/components/marketplace-detail-doc.tsx +8 -4
- package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
- package/src/features/marketplace/hooks/use-marketplace-detail-doc-entry.ts +84 -0
- package/src/features/panel-apps/components/panel-apps-list.tsx +2 -2
- package/src/features/right-panel-resources/components/right-panel-resource-home-page.tsx +1 -1
- package/src/features/settings/pages/__tests__/appearance-settings-page.test.tsx +25 -8
- package/src/features/settings/pages/appearance-settings-page.tsx +92 -13
- package/src/features/side-dock/components/side-dock.tsx +3 -3
- package/src/index.css +275 -15
- package/src/shared/components/__tests__/file-type-icon.test.tsx +61 -0
- package/src/shared/components/actions/action-link.tsx +1 -1
- package/src/shared/components/doc-browser/__tests__/doc-browser-context.test.tsx +19 -0
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +16 -0
- package/src/shared/components/doc-browser/doc-browser-context.tsx +1 -0
- package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +1 -1
- package/src/shared/components/doc-browser/doc-browser.tsx +11 -3
- package/src/shared/components/doc-browser/managers/doc-browser.manager.ts +5 -0
- package/src/shared/components/doc-browser/stores/doc-browser.store.ts +6 -1
- package/src/shared/components/doc-browser/types/doc-browser.types.ts +2 -0
- package/src/shared/components/doc-browser/utils/doc-browser-state.utils.ts +11 -0
- package/src/shared/components/file-type-icon.tsx +272 -0
- package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +22 -0
- package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +17 -2
- package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
- package/src/shared/components/ui/button.tsx +1 -1
- package/src/shared/components/ui/dialog.tsx +1 -1
- package/src/shared/components/ui/input.tsx +1 -1
- package/src/shared/components/ui/select.tsx +1 -1
- package/src/shared/components/ui/switch.tsx +1 -1
- package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +38 -0
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +82 -2
- package/src/shared/components/ui/tabs.tsx +1 -1
- package/src/shared/components/ui/textarea.tsx +1 -1
- package/src/shared/lib/api/__tests__/server-path.utils.test.ts +28 -0
- package/src/shared/lib/api/utils/server-path.utils.ts +19 -20
- package/src/shared/lib/i18n/locales/en-US/chat.json +99 -0
- package/src/shared/lib/i18n/locales/en-US/core.json +6 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +99 -0
- package/src/shared/lib/i18n/locales/zh-CN/core.json +6 -0
- package/dist/assets/api-B7Qigvtm.js +0 -13
- package/dist/assets/appearance-settings-page-CuE0Iiqj.js +0 -1
- package/dist/assets/channels-list-page-CTsM6TcP.js +0 -8
- package/dist/assets/chat-page-C_5dcuE3.js +0 -1
- package/dist/assets/config-split-page-Fbb4PtTf.js +0 -1
- package/dist/assets/confirm-dialog-D2EG3nqE.js +0 -5
- package/dist/assets/desktop-update-config-BGR3HUi1.js +0 -1
- package/dist/assets/dist-7JTjycxE.js +0 -1
- package/dist/assets/dist-wXLhk4hl.js +0 -1
- package/dist/assets/doc-browser-bHyXnxlj.js +0 -1
- package/dist/assets/doc-browser-context-CYAGm5d5.js +0 -1
- package/dist/assets/doc-browser-gTrQ3jCF.js +0 -1
- package/dist/assets/es2015-j1SRCIX5.js +0 -41
- package/dist/assets/i18n-provider-B4oMxOFx.js +0 -1
- package/dist/assets/index-CvrvblgX.css +0 -1
- package/dist/assets/index-Obd4JYU2.js +0 -104
- package/dist/assets/loader-circle-CdzgK4eH.js +0 -1
- package/dist/assets/mcp-marketplace-page-Bt7CuOoq.js +0 -9
- package/dist/assets/mcp-marketplace-page-Ck3t78_n.js +0 -1
- package/dist/assets/model-config-page-DeKk9gvE.js +0 -1
- package/dist/assets/plus-Bx7wQbhG.js +0 -1
- package/dist/assets/provider-scoped-model-input-DsH2LF1q.js +0 -1
- package/dist/assets/providers-config-page-BFnGp68F.js +0 -1
- package/dist/assets/react-UirzUuST.js +0 -8
- package/dist/assets/remote-CDkHZtA8.js +0 -1
- package/dist/assets/rotate-cw-1JqxHTuw.js +0 -1
- package/dist/assets/runtime-config-page-BelAqiNG.js +0 -1
- package/dist/assets/search-config-page-zPm6--Ig.js +0 -1
- package/dist/assets/secrets-config-page-Cxyp-KuQ.js +0 -3
- package/dist/assets/security-config-B_gCq9fn.js +0 -1
- package/dist/assets/select-CdSEOwVM.js +0 -1
- package/dist/assets/setting-row-CTAtGexr.js +0 -1
- package/dist/assets/side-dock-DPvakJ0a.js +0 -3
- package/dist/assets/switch-BU_UEULb.js +0 -1
- package/dist/assets/tag-chip-D-WsKoT1.js +0 -1
- package/dist/assets/tooltip-CjkOaHW7.js +0 -1
- package/dist/assets/use-config--hx5oxQn.js +0 -1
- package/dist/assets/use-confirm-dialog-CD9a_SK1.js +0 -1
- package/dist/assets/x-DT5x45JU.js +0 -1
- /package/dist/assets/{config-hints-C_iP1zl_.js → config-hints-fDrYfl0l.js} +0 -0
- /package/dist/assets/{host-capabilities-9bB_998Z.js → host-capabilities-zZvY9U63.js} +0 -0
- /package/dist/assets/{middleware-BILWbJE4.js → middleware-BLMHv9YF.js} +0 -0
package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx
CHANGED
|
@@ -2,7 +2,6 @@ import { useMemo } from "react";
|
|
|
2
2
|
import type {
|
|
3
3
|
ChatFileOpenActionViewModel,
|
|
4
4
|
ChatFileOperationBlockViewModel,
|
|
5
|
-
ChatFilePreviewViewer,
|
|
6
5
|
} from "@nextclaw/agent-chat-ui";
|
|
7
6
|
import {
|
|
8
7
|
ChatMessageMarkdown,
|
|
@@ -11,6 +10,11 @@ import {
|
|
|
11
10
|
import type { ChatWorkspaceFileTab } from "@/features/chat/stores/chat-thread.store";
|
|
12
11
|
import { ChatSessionWorkspaceDirectoryBrowser } from "./chat-session-workspace-directory-browser";
|
|
13
12
|
import { ChatSessionWorkspaceFileBreadcrumbs } from "./chat-session-workspace-file-breadcrumbs";
|
|
13
|
+
import {
|
|
14
|
+
resolveWorkspaceFileContentKind,
|
|
15
|
+
WorkspaceFileContentPreview,
|
|
16
|
+
type WorkspaceFileContentKind,
|
|
17
|
+
} from "./workspace-file-content-preview";
|
|
14
18
|
import { useServerPathBrowse } from "@/shared/hooks/use-server-path-browse";
|
|
15
19
|
import { useServerPathRead } from "@/shared/hooks/use-server-path-read";
|
|
16
20
|
import { buildServerPathContentUrl } from "@/shared/lib/api";
|
|
@@ -21,6 +25,7 @@ import {
|
|
|
21
25
|
import { t } from "@/shared/lib/i18n";
|
|
22
26
|
import { buildWorkspaceFileBreadcrumb } from "@/shared/lib/session-project";
|
|
23
27
|
import { cn } from "@/shared/lib/utils";
|
|
28
|
+
import { resolveWorkspaceFileViewer } from "@/features/chat/features/workspace/utils/chat-workspace-file-viewer.utils";
|
|
24
29
|
|
|
25
30
|
function inferPreviewKind(params: {
|
|
26
31
|
path: string;
|
|
@@ -32,14 +37,10 @@ function inferPreviewKind(params: {
|
|
|
32
37
|
return /\.mdx?$/i.test(params.path) ? "markdown" : "text";
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return params.viewer === "rendered" && /\.html?$/i.test(params.path) ? "rendered" : "source";
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function appendPreviewRefreshVersion(url: string, refreshVersion: number): string {
|
|
40
|
+
function appendPreviewRefreshVersion(
|
|
41
|
+
url: string,
|
|
42
|
+
refreshVersion: number,
|
|
43
|
+
): string {
|
|
43
44
|
if (refreshVersion <= 0) {
|
|
44
45
|
return url;
|
|
45
46
|
}
|
|
@@ -155,46 +156,50 @@ function WorkspaceCodeSurface({
|
|
|
155
156
|
block,
|
|
156
157
|
}: {
|
|
157
158
|
block: ChatFileOperationBlockViewModel;
|
|
158
|
-
}) {
|
|
159
|
-
return <div className="h-full overflow-auto custom-scrollbar bg-white"><FileOperationCodeSurface block={block} layout="workspace" /></div>;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function WorkspaceHtmlRenderedPreview({
|
|
163
|
-
src,
|
|
164
|
-
}: {
|
|
165
|
-
src: string;
|
|
166
159
|
}) {
|
|
167
160
|
return (
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
data-testid="workspace-html-preview"
|
|
172
|
-
src={src}
|
|
173
|
-
title={t("chatWorkspaceHtmlPreviewTitle")}
|
|
174
|
-
/>
|
|
161
|
+
<div className="h-full overflow-auto custom-scrollbar bg-white">
|
|
162
|
+
<FileOperationCodeSurface block={block} layout="workspace" />
|
|
163
|
+
</div>
|
|
175
164
|
);
|
|
176
165
|
}
|
|
177
166
|
|
|
178
167
|
function WorkspacePreviewBody({
|
|
168
|
+
contentUrl,
|
|
169
|
+
contentUrlKind,
|
|
170
|
+
contentLabel,
|
|
179
171
|
directoryQuery,
|
|
172
|
+
fileBasePath,
|
|
180
173
|
onFileOpen,
|
|
181
174
|
previewBlock,
|
|
182
175
|
previewKind,
|
|
176
|
+
previewViewer,
|
|
183
177
|
previewQuery,
|
|
184
178
|
previewText,
|
|
185
|
-
previewUrl,
|
|
186
|
-
previewViewer,
|
|
187
179
|
}: {
|
|
188
|
-
|
|
180
|
+
contentUrl: string | null;
|
|
181
|
+
contentUrlKind: WorkspaceFileContentKind | null;
|
|
182
|
+
contentLabel: string;
|
|
183
|
+
directoryQuery: ReturnType<typeof useServerPathBrowse> | null | undefined;
|
|
184
|
+
fileBasePath: string | null;
|
|
189
185
|
onFileOpen: (action: ChatFileOpenActionViewModel) => void;
|
|
190
186
|
previewBlock: ChatFileOperationBlockViewModel | null;
|
|
191
187
|
previewKind: "text" | "markdown" | "binary";
|
|
192
|
-
|
|
188
|
+
previewViewer: "source" | "rendered" | null;
|
|
189
|
+
previewQuery: ReturnType<typeof useServerPathRead> | null | undefined;
|
|
193
190
|
previewText: string | null;
|
|
194
|
-
previewUrl: string | null;
|
|
195
|
-
previewViewer: "source" | "rendered";
|
|
196
191
|
}) {
|
|
197
|
-
if (
|
|
192
|
+
if (contentUrl && contentUrlKind) {
|
|
193
|
+
return (
|
|
194
|
+
<WorkspaceFileContentPreview
|
|
195
|
+
contentUrl={contentUrl}
|
|
196
|
+
kind={contentUrlKind}
|
|
197
|
+
label={contentLabel}
|
|
198
|
+
/>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (directoryQuery?.data) {
|
|
198
203
|
return (
|
|
199
204
|
<ChatSessionWorkspaceDirectoryBrowser
|
|
200
205
|
browseQuery={directoryQuery}
|
|
@@ -204,25 +209,25 @@ function WorkspacePreviewBody({
|
|
|
204
209
|
);
|
|
205
210
|
}
|
|
206
211
|
|
|
207
|
-
if (directoryQuery
|
|
212
|
+
if (directoryQuery?.isLoading && previewQuery?.error && !previewBlock) {
|
|
208
213
|
return (
|
|
209
214
|
<WorkspaceFilePreviewStatus text={t("chatWorkspaceLoadingDirectory")} />
|
|
210
215
|
);
|
|
211
216
|
}
|
|
212
217
|
|
|
213
|
-
if ((directoryQuery
|
|
218
|
+
if ((directoryQuery?.isLoading || previewQuery?.isLoading) && !previewBlock) {
|
|
214
219
|
return (
|
|
215
220
|
<WorkspaceFilePreviewStatus text={t("chatWorkspaceLoadingPreview")} />
|
|
216
221
|
);
|
|
217
222
|
}
|
|
218
223
|
|
|
219
|
-
if (previewQuery
|
|
224
|
+
if (previewQuery?.data?.kind === "binary") {
|
|
220
225
|
return (
|
|
221
226
|
<WorkspaceFilePreviewStatus text={t("chatWorkspacePreviewUnsupported")} />
|
|
222
227
|
);
|
|
223
228
|
}
|
|
224
229
|
|
|
225
|
-
if (previewQuery
|
|
230
|
+
if (previewQuery?.error && !previewBlock) {
|
|
226
231
|
return (
|
|
227
232
|
<WorkspaceFilePreviewStatus
|
|
228
233
|
tone="error"
|
|
@@ -235,11 +240,7 @@ function WorkspacePreviewBody({
|
|
|
235
240
|
);
|
|
236
241
|
}
|
|
237
242
|
|
|
238
|
-
if (
|
|
239
|
-
return <WorkspaceHtmlRenderedPreview src={previewUrl} />;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (previewKind === "markdown" && previewText) {
|
|
243
|
+
if (previewKind === "markdown" && previewViewer !== "source" && previewText) {
|
|
243
244
|
return (
|
|
244
245
|
<div className="h-full overflow-auto custom-scrollbar px-5 py-4">
|
|
245
246
|
<ChatMessageMarkdown
|
|
@@ -250,6 +251,9 @@ function WorkspacePreviewBody({
|
|
|
250
251
|
copiedCodeLabel: t("chatCodeCopied"),
|
|
251
252
|
}}
|
|
252
253
|
onFileOpen={onFileOpen}
|
|
254
|
+
resolveFileContentUrl={(action) =>
|
|
255
|
+
buildServerPathContentUrl(action.path, fileBasePath)
|
|
256
|
+
}
|
|
253
257
|
/>
|
|
254
258
|
</div>
|
|
255
259
|
);
|
|
@@ -278,62 +282,87 @@ export function ChatSessionWorkspaceFilePreview({
|
|
|
278
282
|
onFileOpen,
|
|
279
283
|
}: ChatSessionWorkspaceFilePreviewProps) {
|
|
280
284
|
const isPreviewMode = file.viewMode === "preview";
|
|
285
|
+
const suppliedContentUrl = file.contentUrl?.trim() || null;
|
|
286
|
+
const usesServerPath = isPreviewMode && !suppliedContentUrl;
|
|
281
287
|
const previewQuery = useServerPathRead({
|
|
282
288
|
path: file.path,
|
|
283
289
|
basePath: sessionWorkingDir,
|
|
284
|
-
enabled:
|
|
290
|
+
enabled: usesServerPath,
|
|
285
291
|
});
|
|
286
292
|
const directoryQuery = useServerPathBrowse({
|
|
287
293
|
path: file.path,
|
|
288
294
|
basePath: sessionWorkingDir,
|
|
289
295
|
includeFiles: true,
|
|
290
|
-
enabled:
|
|
296
|
+
enabled: usesServerPath,
|
|
291
297
|
});
|
|
292
298
|
const diffBlock = useMemo(
|
|
293
299
|
() => (file.viewMode === "diff" ? buildDiffBlock(file) : null),
|
|
294
300
|
[file],
|
|
295
301
|
);
|
|
296
|
-
const previewText =
|
|
297
|
-
|
|
302
|
+
const previewText = isPreviewMode
|
|
303
|
+
? (previewQuery?.data?.text ?? file.rawText ?? null)
|
|
304
|
+
: null;
|
|
298
305
|
const previewKind = inferPreviewKind({
|
|
299
|
-
path: previewQuery
|
|
300
|
-
serverKind: previewQuery
|
|
306
|
+
path: previewQuery?.data?.resolvedPath ?? file.path,
|
|
307
|
+
serverKind: previewQuery?.data?.kind,
|
|
301
308
|
});
|
|
309
|
+
const suppliedContentKind = suppliedContentUrl
|
|
310
|
+
? resolveWorkspaceFileContentKind({
|
|
311
|
+
path: file.path,
|
|
312
|
+
mimeType: file.mimeType,
|
|
313
|
+
})
|
|
314
|
+
: null;
|
|
302
315
|
const resolvedPath =
|
|
303
|
-
directoryQuery
|
|
304
|
-
previewQuery
|
|
316
|
+
directoryQuery?.data?.currentPath ??
|
|
317
|
+
previewQuery?.data?.resolvedPath ??
|
|
305
318
|
file.path;
|
|
306
|
-
const previewPathKind = directoryQuery
|
|
307
|
-
const previewViewer =
|
|
319
|
+
const previewPathKind = directoryQuery?.data ? "directory" : "file";
|
|
320
|
+
const previewViewer = resolveWorkspaceFileViewer(
|
|
321
|
+
resolvedPath,
|
|
322
|
+
file.previewViewer,
|
|
323
|
+
);
|
|
324
|
+
const localContentKind = resolveWorkspaceFileContentKind({
|
|
308
325
|
path: resolvedPath,
|
|
309
|
-
viewer: file.previewViewer,
|
|
310
326
|
});
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
327
|
+
const localContentUrlCandidate = buildServerPathContentUrl(
|
|
328
|
+
file.path,
|
|
329
|
+
sessionWorkingDir,
|
|
330
|
+
);
|
|
331
|
+
const shouldRenderLocalContent = Boolean(
|
|
332
|
+
!suppliedContentUrl &&
|
|
333
|
+
isPreviewMode &&
|
|
334
|
+
localContentUrlCandidate &&
|
|
335
|
+
file.previewViewer !== "source" &&
|
|
336
|
+
localContentKind !== "other" &&
|
|
337
|
+
(localContentKind !== "html" || previewViewer === "rendered"),
|
|
338
|
+
);
|
|
339
|
+
const localContentUrl =
|
|
340
|
+
shouldRenderLocalContent && localContentUrlCandidate
|
|
341
|
+
? appendPreviewRefreshVersion(localContentUrlCandidate, refreshVersion)
|
|
317
342
|
: null;
|
|
343
|
+
const contentUrl = suppliedContentUrl ?? localContentUrl;
|
|
344
|
+
const contentUrlKind =
|
|
345
|
+
suppliedContentKind ?? (localContentUrl ? localContentKind : null);
|
|
318
346
|
const previewBlock = useMemo(() => {
|
|
319
|
-
if (!isPreviewMode || !previewText) {
|
|
347
|
+
if (!isPreviewMode || !previewText || contentUrl) {
|
|
320
348
|
return null;
|
|
321
349
|
}
|
|
322
350
|
return buildPreviewBlock({
|
|
323
|
-
path: previewQuery
|
|
351
|
+
path: previewQuery?.data?.resolvedPath ?? file.path,
|
|
324
352
|
text: previewText,
|
|
325
|
-
languageHint: previewQuery
|
|
353
|
+
languageHint: previewQuery?.data?.languageHint ?? null,
|
|
326
354
|
line: file.line,
|
|
327
355
|
});
|
|
328
356
|
}, [
|
|
357
|
+
contentUrl,
|
|
329
358
|
file.line,
|
|
330
359
|
file.path,
|
|
331
360
|
isPreviewMode,
|
|
332
|
-
previewQuery
|
|
333
|
-
previewQuery
|
|
361
|
+
previewQuery?.data?.languageHint,
|
|
362
|
+
previewQuery?.data?.resolvedPath,
|
|
334
363
|
previewText,
|
|
335
364
|
]);
|
|
336
|
-
const
|
|
365
|
+
const isTextPreviewTruncated = !contentUrl && Boolean(previewQuery?.data?.truncated);
|
|
337
366
|
const breadcrumbBasePath = sessionProjectRoot ?? sessionWorkingDir;
|
|
338
367
|
const breadcrumb = useMemo(
|
|
339
368
|
() =>
|
|
@@ -343,13 +372,13 @@ export function ChatSessionWorkspaceFilePreview({
|
|
|
343
372
|
sessionProjectRoot: breadcrumbBasePath,
|
|
344
373
|
line: file.line,
|
|
345
374
|
column: file.column,
|
|
346
|
-
truncated:
|
|
375
|
+
truncated: isTextPreviewTruncated,
|
|
347
376
|
}),
|
|
348
377
|
[
|
|
349
378
|
breadcrumbBasePath,
|
|
350
379
|
file.column,
|
|
351
380
|
file.line,
|
|
352
|
-
|
|
381
|
+
isTextPreviewTruncated,
|
|
353
382
|
previewPathKind,
|
|
354
383
|
resolvedPath,
|
|
355
384
|
],
|
|
@@ -367,14 +396,17 @@ export function ChatSessionWorkspaceFilePreview({
|
|
|
367
396
|
<WorkspaceDiffBody diffBlock={diffBlock} />
|
|
368
397
|
) : (
|
|
369
398
|
<WorkspacePreviewBody
|
|
399
|
+
contentUrl={contentUrl}
|
|
400
|
+
contentUrlKind={contentUrlKind}
|
|
401
|
+
contentLabel={file.label?.trim() || resolvedPath}
|
|
370
402
|
directoryQuery={directoryQuery}
|
|
403
|
+
fileBasePath={sessionWorkingDir}
|
|
371
404
|
onFileOpen={onFileOpen}
|
|
372
405
|
previewBlock={previewBlock}
|
|
373
406
|
previewKind={previewKind}
|
|
407
|
+
previewViewer={previewViewer}
|
|
374
408
|
previewQuery={previewQuery}
|
|
375
409
|
previewText={previewText}
|
|
376
|
-
previewUrl={previewUrl}
|
|
377
|
-
previewViewer={previewViewer}
|
|
378
410
|
/>
|
|
379
411
|
)}
|
|
380
412
|
</div>
|
package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx
CHANGED
|
@@ -1,21 +1,234 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import {
|
|
3
|
+
AlarmClock,
|
|
4
|
+
ChevronRight,
|
|
5
|
+
FolderTree,
|
|
6
|
+
GitBranch,
|
|
7
|
+
MessageSquarePlus,
|
|
8
|
+
} from "lucide-react";
|
|
2
9
|
import type { CronJobView } from "@/shared/lib/api";
|
|
3
10
|
import { usePresenter } from "@/features/chat/components/providers/chat-presenter.provider";
|
|
4
11
|
import { SessionConversationArea } from "@/features/chat/features/conversation/components/session-conversation-area";
|
|
5
12
|
import { ChatSessionWorkspaceFilePreview } from "@/features/chat/features/workspace/components/chat-session-workspace-file-preview";
|
|
13
|
+
import { ChatSessionWorkspaceDirectoryBrowser } from "@/features/chat/features/workspace/components/chat-session-workspace-directory-browser";
|
|
6
14
|
import { SessionCronJobContent } from "@/features/chat/features/workspace/components/session-cron-job-content";
|
|
7
15
|
import type { ResolvedChildSessionTab } from "@/features/chat/features/ncp/hooks/use-ncp-child-session-tabs-view";
|
|
8
16
|
import type { WorkspaceSelection } from "@/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils";
|
|
17
|
+
import { useServerPathBrowse } from "@/shared/hooks/use-server-path-browse";
|
|
9
18
|
import { t } from "@/shared/lib/i18n";
|
|
19
|
+
import { cn } from "@/shared/lib/utils";
|
|
10
20
|
|
|
11
21
|
type ChatSessionWorkspacePanelContentProps = {
|
|
12
22
|
activeSelection: WorkspaceSelection;
|
|
23
|
+
childSessionTabs: readonly ResolvedChildSessionTab[];
|
|
13
24
|
filePreviewRefreshVersion: number;
|
|
25
|
+
sessionKey: string | null;
|
|
14
26
|
sessionCronJobs: readonly CronJobView[];
|
|
15
27
|
sessionProjectRoot: string | null;
|
|
16
28
|
sessionWorkingDir: string | null;
|
|
17
29
|
};
|
|
18
30
|
|
|
31
|
+
function WorkspaceOverviewEntry({
|
|
32
|
+
count,
|
|
33
|
+
description,
|
|
34
|
+
icon,
|
|
35
|
+
onClick,
|
|
36
|
+
title,
|
|
37
|
+
}: {
|
|
38
|
+
count?: number;
|
|
39
|
+
description: string;
|
|
40
|
+
icon: ReactNode;
|
|
41
|
+
onClick: () => void;
|
|
42
|
+
title: string;
|
|
43
|
+
}) {
|
|
44
|
+
return (
|
|
45
|
+
<button
|
|
46
|
+
type="button"
|
|
47
|
+
className="group flex w-full items-center gap-3 rounded-lg border border-gray-200/80 bg-white px-3 py-3 text-left transition-colors hover:border-gray-300 hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
|
|
48
|
+
onClick={onClick}
|
|
49
|
+
>
|
|
50
|
+
<span className="inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-gray-100 text-gray-600">
|
|
51
|
+
{icon}
|
|
52
|
+
</span>
|
|
53
|
+
<span className="min-w-0 flex-1">
|
|
54
|
+
<span className="flex items-center gap-2 text-sm font-medium text-gray-900">
|
|
55
|
+
<span className="truncate">{title}</span>
|
|
56
|
+
{typeof count === "number" ? (
|
|
57
|
+
<span className="rounded-full bg-gray-100 px-1.5 py-0.5 text-[10px] font-semibold tabular-nums text-gray-500">
|
|
58
|
+
{count}
|
|
59
|
+
</span>
|
|
60
|
+
) : null}
|
|
61
|
+
</span>
|
|
62
|
+
<span className="mt-0.5 block text-xs leading-5 text-gray-500">
|
|
63
|
+
{description}
|
|
64
|
+
</span>
|
|
65
|
+
</span>
|
|
66
|
+
<ChevronRight className="h-4 w-4 shrink-0 text-gray-300 transition-transform group-hover:translate-x-0.5 group-hover:text-gray-500" />
|
|
67
|
+
</button>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function WorkspaceOverview({
|
|
72
|
+
childSessionTabs,
|
|
73
|
+
sessionCronJobs,
|
|
74
|
+
sessionKey,
|
|
75
|
+
}: {
|
|
76
|
+
childSessionTabs: readonly ResolvedChildSessionTab[];
|
|
77
|
+
sessionCronJobs: readonly CronJobView[];
|
|
78
|
+
sessionKey: string | null;
|
|
79
|
+
}) {
|
|
80
|
+
const presenter = usePresenter();
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div className="h-full overflow-auto bg-gray-50/45 px-4 py-5 custom-scrollbar">
|
|
84
|
+
<div className="mx-auto max-w-xl">
|
|
85
|
+
<h2 className="text-base font-semibold text-gray-900">
|
|
86
|
+
{t("chatWorkspaceOverview")}
|
|
87
|
+
</h2>
|
|
88
|
+
<p className="mt-1 text-xs leading-5 text-gray-500">
|
|
89
|
+
{t("chatWorkspaceOverviewDescription")}
|
|
90
|
+
</p>
|
|
91
|
+
<div className="mt-4 space-y-2">
|
|
92
|
+
<WorkspaceOverviewEntry
|
|
93
|
+
count={childSessionTabs.length}
|
|
94
|
+
description={t("chatWorkspaceChildSessionsDescription")}
|
|
95
|
+
icon={<GitBranch className="h-4 w-4" />}
|
|
96
|
+
title={t("chatWorkspaceChildSessions")}
|
|
97
|
+
onClick={() => {
|
|
98
|
+
if (sessionKey) {
|
|
99
|
+
presenter.chatThreadManager.openChildSessions(sessionKey);
|
|
100
|
+
}
|
|
101
|
+
}}
|
|
102
|
+
/>
|
|
103
|
+
<WorkspaceOverviewEntry
|
|
104
|
+
count={sessionCronJobs.length}
|
|
105
|
+
description={t("chatWorkspaceSessionCronJobsDescription")}
|
|
106
|
+
icon={<AlarmClock className="h-4 w-4" />}
|
|
107
|
+
title={t("chatWorkspaceSessionCronJobs")}
|
|
108
|
+
onClick={() => {
|
|
109
|
+
if (sessionKey) {
|
|
110
|
+
presenter.chatThreadManager.openSessionCronPanel(sessionKey);
|
|
111
|
+
}
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
114
|
+
<WorkspaceOverviewEntry
|
|
115
|
+
description={t("chatWorkspaceProjectFilesDescription")}
|
|
116
|
+
icon={<FolderTree className="h-4 w-4" />}
|
|
117
|
+
title={t("chatWorkspaceProjectFiles")}
|
|
118
|
+
onClick={() => {
|
|
119
|
+
if (sessionKey) {
|
|
120
|
+
presenter.chatThreadManager.openProjectFiles(sessionKey);
|
|
121
|
+
}
|
|
122
|
+
}}
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function WorkspaceChildSessions({
|
|
131
|
+
childSessionTabs,
|
|
132
|
+
}: {
|
|
133
|
+
childSessionTabs: readonly ResolvedChildSessionTab[];
|
|
134
|
+
}) {
|
|
135
|
+
const presenter = usePresenter();
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<div className="h-full overflow-auto bg-gray-50/45 px-4 py-5 custom-scrollbar">
|
|
139
|
+
<div className="mx-auto max-w-xl">
|
|
140
|
+
<div className="flex items-center gap-2">
|
|
141
|
+
<h2 className="text-base font-semibold text-gray-900">
|
|
142
|
+
{t("chatWorkspaceChildSessions")}
|
|
143
|
+
</h2>
|
|
144
|
+
<span className="rounded-full bg-gray-100 px-1.5 py-0.5 text-[10px] font-semibold tabular-nums text-gray-500">
|
|
145
|
+
{childSessionTabs.length}
|
|
146
|
+
</span>
|
|
147
|
+
</div>
|
|
148
|
+
{childSessionTabs.length === 0 ? (
|
|
149
|
+
<div className="py-10 text-center text-sm text-gray-500">
|
|
150
|
+
{t("chatWorkspaceChildSessionsEmpty")}
|
|
151
|
+
</div>
|
|
152
|
+
) : (
|
|
153
|
+
<div className="mt-4 space-y-2">
|
|
154
|
+
{childSessionTabs.map((tab) => (
|
|
155
|
+
<button
|
|
156
|
+
key={tab.sessionKey}
|
|
157
|
+
type="button"
|
|
158
|
+
className="group flex w-full items-center gap-3 rounded-lg border border-gray-200/80 bg-white px-3 py-3 text-left transition-colors hover:border-gray-300 hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
|
|
159
|
+
onClick={() =>
|
|
160
|
+
presenter.chatThreadManager.selectChildSessionDetail(
|
|
161
|
+
tab.sessionKey,
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
>
|
|
165
|
+
<span className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gray-100 text-gray-600">
|
|
166
|
+
<GitBranch className="h-4 w-4" />
|
|
167
|
+
</span>
|
|
168
|
+
<span className="min-w-0 flex-1">
|
|
169
|
+
<span className="block truncate text-sm font-medium text-gray-900">
|
|
170
|
+
{tab.title}
|
|
171
|
+
</span>
|
|
172
|
+
{tab.projectName || tab.sessionTypeLabel ? (
|
|
173
|
+
<span className="mt-0.5 block truncate text-xs text-gray-500">
|
|
174
|
+
{[tab.sessionTypeLabel, tab.projectName]
|
|
175
|
+
.filter(Boolean)
|
|
176
|
+
.join(" · ")}
|
|
177
|
+
</span>
|
|
178
|
+
) : null}
|
|
179
|
+
</span>
|
|
180
|
+
<ChevronRight className="h-4 w-4 shrink-0 text-gray-300 transition-transform group-hover:translate-x-0.5 group-hover:text-gray-500" />
|
|
181
|
+
</button>
|
|
182
|
+
))}
|
|
183
|
+
</div>
|
|
184
|
+
)}
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function WorkspaceProjectFiles({
|
|
191
|
+
projectRoot,
|
|
192
|
+
workingDir,
|
|
193
|
+
}: {
|
|
194
|
+
projectRoot: string | null;
|
|
195
|
+
workingDir: string | null;
|
|
196
|
+
}) {
|
|
197
|
+
const presenter = usePresenter();
|
|
198
|
+
const rootPath = projectRoot ?? workingDir;
|
|
199
|
+
const browseQuery = useServerPathBrowse({
|
|
200
|
+
path: rootPath,
|
|
201
|
+
includeFiles: true,
|
|
202
|
+
enabled: Boolean(rootPath),
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
if (!rootPath) {
|
|
206
|
+
return (
|
|
207
|
+
<div className="flex h-full items-center justify-center px-6 text-center text-sm text-gray-500">
|
|
208
|
+
{t("chatWorkspaceProjectFilesUnavailable")}
|
|
209
|
+
</div>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return (
|
|
214
|
+
<ChatSessionWorkspaceDirectoryBrowser
|
|
215
|
+
browseQuery={browseQuery}
|
|
216
|
+
onFileOpen={presenter.chatThreadManager.openFilePreview}
|
|
217
|
+
renderStatus={({ text, tone = "muted" }) => (
|
|
218
|
+
<div
|
|
219
|
+
className={cn(
|
|
220
|
+
"flex h-full items-center justify-center px-6 text-center text-sm",
|
|
221
|
+
tone === "error" ? "text-rose-600" : "text-gray-500",
|
|
222
|
+
)}
|
|
223
|
+
>
|
|
224
|
+
{text}
|
|
225
|
+
</div>
|
|
226
|
+
)}
|
|
227
|
+
showRoot
|
|
228
|
+
/>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
19
232
|
function ChildSessionMetaChip({ value }: { value: string }) {
|
|
20
233
|
return (
|
|
21
234
|
<span className="inline-flex max-w-full shrink-0 items-center rounded border border-gray-200 bg-gray-50 px-1.5 py-0.5 text-[10px] font-medium text-gray-600">
|
|
@@ -68,13 +281,38 @@ function WorkspaceSideChatDraftHeader() {
|
|
|
68
281
|
|
|
69
282
|
export function ChatSessionWorkspacePanelContent({
|
|
70
283
|
activeSelection,
|
|
284
|
+
childSessionTabs,
|
|
71
285
|
filePreviewRefreshVersion,
|
|
286
|
+
sessionKey,
|
|
72
287
|
sessionCronJobs,
|
|
73
288
|
sessionProjectRoot,
|
|
74
289
|
sessionWorkingDir,
|
|
75
290
|
}: ChatSessionWorkspacePanelContentProps) {
|
|
76
291
|
const presenter = usePresenter();
|
|
77
292
|
|
|
293
|
+
if (activeSelection.kind === "overview") {
|
|
294
|
+
return (
|
|
295
|
+
<WorkspaceOverview
|
|
296
|
+
childSessionTabs={childSessionTabs}
|
|
297
|
+
sessionCronJobs={sessionCronJobs}
|
|
298
|
+
sessionKey={sessionKey}
|
|
299
|
+
/>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (activeSelection.kind === "project-files") {
|
|
304
|
+
return (
|
|
305
|
+
<WorkspaceProjectFiles
|
|
306
|
+
projectRoot={sessionProjectRoot}
|
|
307
|
+
workingDir={sessionWorkingDir}
|
|
308
|
+
/>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (activeSelection.kind === "child-sessions") {
|
|
313
|
+
return <WorkspaceChildSessions childSessionTabs={childSessionTabs} />;
|
|
314
|
+
}
|
|
315
|
+
|
|
78
316
|
if (activeSelection.kind === "side-chat-draft") {
|
|
79
317
|
return (
|
|
80
318
|
<>
|
package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx
CHANGED
|
@@ -2,7 +2,11 @@ import {
|
|
|
2
2
|
AlarmClock,
|
|
3
3
|
ArrowLeft,
|
|
4
4
|
ArrowRight,
|
|
5
|
-
|
|
5
|
+
Code2,
|
|
6
|
+
Eye,
|
|
7
|
+
FolderTree,
|
|
8
|
+
GitBranch,
|
|
9
|
+
LayoutDashboard,
|
|
6
10
|
Maximize2,
|
|
7
11
|
MessageSquarePlus,
|
|
8
12
|
MessageSquareText,
|
|
@@ -12,6 +16,7 @@ import {
|
|
|
12
16
|
} from "lucide-react";
|
|
13
17
|
import type { WorkspaceTabViewModel } from "@/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils";
|
|
14
18
|
import { AgentIdentityAvatar } from "@/shared/components/common/agent-identity";
|
|
19
|
+
import { FileTypeIcon } from "@/shared/components/file-type-icon";
|
|
15
20
|
import {
|
|
16
21
|
CompactTabStrip,
|
|
17
22
|
type CompactTabStripAction,
|
|
@@ -19,13 +24,29 @@ import {
|
|
|
19
24
|
} from "@/shared/components/ui/tab-strip/compact-tab-strip";
|
|
20
25
|
import { t } from "@/shared/lib/i18n";
|
|
21
26
|
|
|
22
|
-
function WorkspaceTabIcon({
|
|
27
|
+
function WorkspaceTabIcon({
|
|
28
|
+
agentId,
|
|
29
|
+
fileName,
|
|
30
|
+
kind,
|
|
31
|
+
}: Pick<WorkspaceTabViewModel, "agentId" | "fileName" | "kind">) {
|
|
32
|
+
if (kind === "overview") {
|
|
33
|
+
return <LayoutDashboard className="h-3.5 w-3.5 shrink-0 text-gray-400" />;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (kind === "child-sessions") {
|
|
37
|
+
return <GitBranch className="h-3.5 w-3.5 shrink-0 text-gray-400" />;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (kind === "project-files") {
|
|
41
|
+
return <FolderTree className="h-3.5 w-3.5 shrink-0 text-gray-400" />;
|
|
42
|
+
}
|
|
43
|
+
|
|
23
44
|
if (kind === "cron") {
|
|
24
45
|
return <AlarmClock className="h-3.5 w-3.5 shrink-0 text-gray-400" />;
|
|
25
46
|
}
|
|
26
47
|
|
|
27
48
|
if (kind === "file") {
|
|
28
|
-
return <
|
|
49
|
+
return <FileTypeIcon fileName={fileName ?? ""} size="compact" />;
|
|
29
50
|
}
|
|
30
51
|
|
|
31
52
|
if (kind === "side-chat-draft") {
|
|
@@ -47,11 +68,17 @@ function buildCompactWorkspaceTabs(
|
|
|
47
68
|
return tabs.map((tab) => ({
|
|
48
69
|
key: tab.key,
|
|
49
70
|
label: tab.title,
|
|
71
|
+
labelClassName: tab.isRenderedPreview ? "italic font-normal" : undefined,
|
|
50
72
|
active: tab.active,
|
|
51
73
|
tooltip: tab.tooltip,
|
|
52
|
-
leadingIcon:
|
|
53
|
-
|
|
54
|
-
|
|
74
|
+
leadingIcon: (
|
|
75
|
+
<WorkspaceTabIcon
|
|
76
|
+
kind={tab.kind}
|
|
77
|
+
agentId={tab.agentId}
|
|
78
|
+
fileName={tab.fileName}
|
|
79
|
+
/>
|
|
80
|
+
),
|
|
81
|
+
badge: tab.kind === "file" && tab.viewMode === "diff" ? (
|
|
55
82
|
<span className="shrink-0 rounded border border-amber-200 bg-amber-50 px-1 py-0 text-[9px] font-medium uppercase tracking-[0.08em] text-amber-700">
|
|
56
83
|
{t("chatWorkspaceDiff")}
|
|
57
84
|
</span>
|
|
@@ -61,6 +88,29 @@ function buildCompactWorkspaceTabs(
|
|
|
61
88
|
closePlacement: "leading-hover",
|
|
62
89
|
onSelect: tab.onSelect,
|
|
63
90
|
onClose: tab.onClose,
|
|
91
|
+
menuLabel: t("chatWorkspaceFileMoreActions"),
|
|
92
|
+
menuActions: tab.kind === "file"
|
|
93
|
+
? [
|
|
94
|
+
...(tab.alternateViewerAction
|
|
95
|
+
? [{
|
|
96
|
+
key: `viewer:${tab.alternateViewerAction.viewer}`,
|
|
97
|
+
icon: tab.alternateViewerAction.viewer === "rendered"
|
|
98
|
+
? <Eye className="h-3.5 w-3.5" />
|
|
99
|
+
: <Code2 className="h-3.5 w-3.5" />,
|
|
100
|
+
label: tab.alternateViewerAction.label,
|
|
101
|
+
onClick: tab.alternateViewerAction.onSelect,
|
|
102
|
+
}]
|
|
103
|
+
: []),
|
|
104
|
+
...(tab.onClose
|
|
105
|
+
? [{
|
|
106
|
+
key: "close",
|
|
107
|
+
icon: <X className="h-3.5 w-3.5" />,
|
|
108
|
+
label: t("chatWorkspaceCloseFile"),
|
|
109
|
+
onClick: tab.onClose,
|
|
110
|
+
}]
|
|
111
|
+
: []),
|
|
112
|
+
]
|
|
113
|
+
: undefined,
|
|
64
114
|
}));
|
|
65
115
|
}
|
|
66
116
|
|