修正文件处理
parent
500dc23489
commit
20ab8b28e7
|
|
@ -462,6 +462,7 @@
|
||||||
.ops-attach-link {
|
.ops-attach-link {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
|
|
@ -472,6 +473,14 @@
|
||||||
background: color-mix(in oklab, var(--panel) 78%, transparent);
|
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 {
|
.ops-attach-link:hover {
|
||||||
border-color: color-mix(in oklab, var(--brand) 56%, var(--line) 44%);
|
border-color: color-mix(in oklab, var(--brand) 56%, var(--line) 44%);
|
||||||
}
|
}
|
||||||
|
|
@ -1409,11 +1418,14 @@
|
||||||
max-height: calc(100vh - 170px);
|
max-height: calc(100vh - 170px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-preview-header {
|
.modal-title-row.workspace-preview-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
position: relative;
|
||||||
|
padding-right: 72px;
|
||||||
|
min-height: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-preview-header-text {
|
.workspace-preview-header-text {
|
||||||
|
|
@ -1427,6 +1439,9 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-preview-body {
|
.workspace-preview-body {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useEffect, useMemo, useRef, useState, type AnchorHTMLAttributes, type ChangeEvent, type KeyboardEvent, type ReactNode } from 'react';
|
import { useEffect, useMemo, useRef, useState, type AnchorHTMLAttributes, type ChangeEvent, type KeyboardEvent, type ReactNode } from 'react';
|
||||||
import axios from 'axios';
|
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 ReactMarkdown from 'react-markdown';
|
||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
import rehypeRaw from 'rehype-raw';
|
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/';
|
const WORKSPACE_LINK_PREFIX = 'https://workspace.local/open/';
|
||||||
|
|
||||||
function buildWorkspaceLink(path: string) {
|
function buildWorkspaceLink(path: string) {
|
||||||
|
|
@ -426,15 +436,19 @@ export function BotDashboardModule({
|
||||||
const openWorkspacePathFromChat = (path: string) => {
|
const openWorkspacePathFromChat = (path: string) => {
|
||||||
const normalized = String(path || '').trim();
|
const normalized = String(path || '').trim();
|
||||||
if (!normalized) return;
|
if (!normalized) return;
|
||||||
if (isPdfPath(normalized) || isOfficePath(normalized)) {
|
const action = workspaceFileAction(normalized);
|
||||||
|
if (action === 'download') {
|
||||||
triggerWorkspaceFileDownload(normalized);
|
triggerWorkspaceFileDownload(normalized);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isPreviewableWorkspacePath(normalized)) {
|
if (action === 'preview') {
|
||||||
|
void openWorkspaceFilePreview(normalized);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isPreviewableWorkspacePath(normalized) || action === 'unsupported') {
|
||||||
notify(fileNotPreviewableLabel, { tone: 'warning' });
|
notify(fileNotPreviewableLabel, { tone: 'warning' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void openWorkspaceFilePreview(normalized);
|
|
||||||
};
|
};
|
||||||
const renderWorkspaceAwareText = (text: string, keyPrefix: string): ReactNode[] => {
|
const renderWorkspaceAwareText = (text: string, keyPrefix: string): ReactNode[] => {
|
||||||
const source = String(text || '');
|
const source = String(text || '');
|
||||||
|
|
@ -723,6 +737,7 @@ export function BotDashboardModule({
|
||||||
<div className="ops-chat-attachments">
|
<div className="ops-chat-attachments">
|
||||||
{(item.attachments || []).map((rawPath) => {
|
{(item.attachments || []).map((rawPath) => {
|
||||||
const filePath = normalizeDashboardAttachmentPath(rawPath);
|
const filePath = normalizeDashboardAttachmentPath(rawPath);
|
||||||
|
const fileAction = workspaceFileAction(filePath);
|
||||||
const filename = filePath.split('/').pop() || filePath;
|
const filename = filePath.split('/').pop() || filePath;
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
|
|
@ -731,14 +746,18 @@ export function BotDashboardModule({
|
||||||
href="#"
|
href="#"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (isPdfPath(filePath) || isOfficePath(filePath)) {
|
|
||||||
triggerWorkspaceFileDownload(filePath);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
openWorkspacePathFromChat(filePath);
|
openWorkspacePathFromChat(filePath);
|
||||||
}}
|
}}
|
||||||
|
title={fileAction === 'download' ? t.download : fileAction === 'preview' ? t.previewTitle : t.fileNotPreviewable}
|
||||||
>
|
>
|
||||||
{filename}
|
{fileAction === 'download' ? (
|
||||||
|
<Download size={12} className="ops-attach-link-icon" />
|
||||||
|
) : fileAction === 'preview' ? (
|
||||||
|
<Eye size={12} className="ops-attach-link-icon" />
|
||||||
|
) : (
|
||||||
|
<FileText size={12} className="ops-attach-link-icon" />
|
||||||
|
)}
|
||||||
|
<span className="ops-attach-link-name">{filename}</span>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue