From 20ab8b28e7a98b9901ef394ebcc6a17b55a01b09 Mon Sep 17 00:00:00 2001 From: "mula.liu" Date: Mon, 2 Mar 2026 13:55:35 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=96=87=E4=BB=B6=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/dashboard/BotDashboardModule.css | 17 ++++++++- .../modules/dashboard/BotDashboardModule.tsx | 37 ++++++++++++++----- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/frontend/src/modules/dashboard/BotDashboardModule.css b/frontend/src/modules/dashboard/BotDashboardModule.css index 03dd835..ed72aca 100644 --- a/frontend/src/modules/dashboard/BotDashboardModule.css +++ b/frontend/src/modules/dashboard/BotDashboardModule.css @@ -462,6 +462,7 @@ .ops-attach-link { display: inline-flex; align-items: center; + gap: 6px; max-width: 100%; padding: 4px 8px; border: 1px solid var(--line); @@ -472,6 +473,14 @@ background: color-mix(in oklab, var(--panel) 78%, transparent); } +.ops-attach-link-icon { + flex: 0 0 auto; +} + +.ops-attach-link-name { + min-width: 0; +} + .ops-attach-link:hover { border-color: color-mix(in oklab, var(--brand) 56%, var(--line) 44%); } @@ -1409,11 +1418,14 @@ max-height: calc(100vh - 170px); } -.workspace-preview-header { +.modal-title-row.workspace-preview-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; + position: relative; + padding-right: 72px; + min-height: 28px; } .workspace-preview-header-text { @@ -1427,6 +1439,9 @@ align-items: center; gap: 6px; flex: 0 0 auto; + position: absolute; + top: 0; + right: 0; } .workspace-preview-body { diff --git a/frontend/src/modules/dashboard/BotDashboardModule.tsx b/frontend/src/modules/dashboard/BotDashboardModule.tsx index 02fe5a4..b0caf72 100644 --- a/frontend/src/modules/dashboard/BotDashboardModule.tsx +++ b/frontend/src/modules/dashboard/BotDashboardModule.tsx @@ -1,6 +1,6 @@ import { useEffect, useMemo, useRef, useState, type AnchorHTMLAttributes, type ChangeEvent, type KeyboardEvent, type ReactNode } from 'react'; import axios from 'axios'; -import { Activity, Boxes, Check, Clock3, EllipsisVertical, Eye, EyeOff, FileText, FolderOpen, Hammer, Maximize2, MessageSquareText, Minimize2, Paperclip, Plus, Power, PowerOff, RefreshCw, Repeat2, Save, Settings2, SlidersHorizontal, TriangleAlert, Trash2, UserRound, Waypoints, X } from 'lucide-react'; +import { Activity, Boxes, Check, Clock3, Download, EllipsisVertical, Eye, EyeOff, FileText, FolderOpen, Hammer, Maximize2, MessageSquareText, Minimize2, Paperclip, Plus, Power, PowerOff, RefreshCw, Repeat2, Save, Settings2, SlidersHorizontal, TriangleAlert, Trash2, UserRound, Waypoints, X } from 'lucide-react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import rehypeRaw from 'rehype-raw'; @@ -234,6 +234,16 @@ function isPreviewableWorkspacePath(path: string) { ); } +function workspaceFileAction(path: string): 'preview' | 'download' | 'unsupported' { + const normalized = String(path || '').trim(); + if (!normalized) return 'unsupported'; + if (isPdfPath(normalized) || isOfficePath(normalized)) return 'download'; + if (isImagePath(normalized)) return 'preview'; + const lower = normalized.toLowerCase(); + if (['.md', '.json', '.log', '.txt', '.csv'].some((ext) => lower.endsWith(ext))) return 'preview'; + return 'unsupported'; +} + const WORKSPACE_LINK_PREFIX = 'https://workspace.local/open/'; function buildWorkspaceLink(path: string) { @@ -426,15 +436,19 @@ export function BotDashboardModule({ const openWorkspacePathFromChat = (path: string) => { const normalized = String(path || '').trim(); if (!normalized) return; - if (isPdfPath(normalized) || isOfficePath(normalized)) { + const action = workspaceFileAction(normalized); + if (action === 'download') { triggerWorkspaceFileDownload(normalized); return; } - if (!isPreviewableWorkspacePath(normalized)) { + if (action === 'preview') { + void openWorkspaceFilePreview(normalized); + return; + } + if (!isPreviewableWorkspacePath(normalized) || action === 'unsupported') { notify(fileNotPreviewableLabel, { tone: 'warning' }); return; } - void openWorkspaceFilePreview(normalized); }; const renderWorkspaceAwareText = (text: string, keyPrefix: string): ReactNode[] => { const source = String(text || ''); @@ -723,6 +737,7 @@ export function BotDashboardModule({
{(item.attachments || []).map((rawPath) => { const filePath = normalizeDashboardAttachmentPath(rawPath); + const fileAction = workspaceFileAction(filePath); const filename = filePath.split('/').pop() || filePath; return ( { event.preventDefault(); - if (isPdfPath(filePath) || isOfficePath(filePath)) { - triggerWorkspaceFileDownload(filePath); - return; - } openWorkspacePathFromChat(filePath); }} + title={fileAction === 'download' ? t.download : fileAction === 'preview' ? t.previewTitle : t.fileNotPreviewable} > - {filename} + {fileAction === 'download' ? ( + + ) : fileAction === 'preview' ? ( + + ) : ( + + )} + {filename} ); })}