1.45
This commit is contained in:
parent
a798dee401
commit
1aa84e9ffe
@ -73,7 +73,7 @@ export const LogStreamViewer: React.FC<LogStreamViewerProps> = ({
|
|||||||
console.log('[LogStreamViewer] Render - status:', currentStatus, 'error:', error, 'shouldShowError:', shouldShowError, 'isConnecting:', isConnecting);
|
console.log('[LogStreamViewer] Render - status:', currentStatus, 'error:', error, 'shouldShowError:', shouldShowError, 'isConnecting:', isConnecting);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`flex flex-col h-full ${className}`}>
|
<div className={`flex flex-col h-full relative ${className}`}>
|
||||||
{/* 自定义控制栏 */}
|
{/* 自定义控制栏 */}
|
||||||
{customToolbar && (
|
{customToolbar && (
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
@ -82,7 +82,7 @@ export const LogStreamViewer: React.FC<LogStreamViewerProps> = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 日志显示区域 */}
|
{/* 日志显示区域 */}
|
||||||
<div className="flex-1 overflow-hidden">
|
<div className="flex-1 overflow-hidden relative">
|
||||||
{shouldShowError ? (
|
{shouldShowError ? (
|
||||||
<div className="h-full flex items-center justify-center p-4 bg-gray-950">
|
<div className="h-full flex items-center justify-center p-4 bg-gray-950">
|
||||||
<div className="text-center max-w-md">
|
<div className="text-center max-w-md">
|
||||||
|
|||||||
@ -12,6 +12,7 @@ export const MonacoLogViewer: React.FC<MonacoLogViewerProps> = ({
|
|||||||
fontSize = 12,
|
fontSize = 12,
|
||||||
theme = 'vs-dark',
|
theme = 'vs-dark',
|
||||||
height = '100%',
|
height = '100%',
|
||||||
|
wordWrap = false,
|
||||||
onReady,
|
onReady,
|
||||||
className = '',
|
className = '',
|
||||||
style = {},
|
style = {},
|
||||||
@ -27,6 +28,15 @@ export const MonacoLogViewer: React.FC<MonacoLogViewerProps> = ({
|
|||||||
autoScrollRef.current = autoScroll;
|
autoScrollRef.current = autoScroll;
|
||||||
}, [autoScroll]);
|
}, [autoScroll]);
|
||||||
|
|
||||||
|
// 更新wordWrap设置
|
||||||
|
useEffect(() => {
|
||||||
|
if (editorRef.current) {
|
||||||
|
editorRef.current.updateOptions({
|
||||||
|
wordWrap: wordWrap ? 'on' : 'off',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [wordWrap]);
|
||||||
|
|
||||||
// Monaco Editor挂载完成
|
// Monaco Editor挂载完成
|
||||||
const handleEditorDidMount = (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => {
|
const handleEditorDidMount = (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => {
|
||||||
editorRef.current = editor;
|
editorRef.current = editor;
|
||||||
@ -125,7 +135,7 @@ export const MonacoLogViewer: React.FC<MonacoLogViewerProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`w-full h-full ${className}`} style={{ height, ...style }}>
|
<div className={`w-full h-full relative ${className}`} style={{ height, ...style }}>
|
||||||
<Editor
|
<Editor
|
||||||
height="100%"
|
height="100%"
|
||||||
defaultLanguage="plaintext"
|
defaultLanguage="plaintext"
|
||||||
@ -137,7 +147,7 @@ export const MonacoLogViewer: React.FC<MonacoLogViewerProps> = ({
|
|||||||
readOnly: true,
|
readOnly: true,
|
||||||
minimap: { enabled: false },
|
minimap: { enabled: false },
|
||||||
scrollBeyondLastLine: false,
|
scrollBeyondLastLine: false,
|
||||||
wordWrap: 'off',
|
wordWrap: wordWrap ? 'on' : 'off',
|
||||||
lineNumbers: 'on',
|
lineNumbers: 'on',
|
||||||
glyphMargin: false,
|
glyphMargin: false,
|
||||||
folding: false,
|
folding: false,
|
||||||
|
|||||||
@ -159,6 +159,9 @@ export interface MonacoLogViewerProps {
|
|||||||
/** 高度 */
|
/** 高度 */
|
||||||
height?: string | number;
|
height?: string | number;
|
||||||
|
|
||||||
|
/** 自动换行 */
|
||||||
|
wordWrap?: boolean;
|
||||||
|
|
||||||
/** 就绪回调 */
|
/** 就绪回调 */
|
||||||
onReady?: (api: LogViewerAPI) => void;
|
onReady?: (api: LogViewerAPI) => void;
|
||||||
|
|
||||||
|
|||||||
@ -200,8 +200,8 @@ export function TerminalWindowManager<TResource = any>({
|
|||||||
<div
|
<div
|
||||||
key={win.id}
|
key={win.id}
|
||||||
style={{
|
style={{
|
||||||
visibility: win.isMinimized ? 'hidden' : 'visible',
|
// 使用 display:none 彻底隐藏最小化窗口,避免Monaco滚动条残影
|
||||||
pointerEvents: win.isMinimized ? 'none' : 'auto',
|
display: win.isMinimized ? 'none' : 'block',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DraggableWindow
|
<DraggableWindow
|
||||||
|
|||||||
@ -214,8 +214,8 @@ export const DraggableWindow: React.FC<DraggableWindowProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 窗口内容 */}
|
{/* 窗口内容 - relative定位确保子元素的absolute定位正确 */}
|
||||||
<div className="flex-1 overflow-hidden">
|
<div className="flex-1 overflow-hidden relative">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import {
|
|||||||
Loader2,
|
Loader2,
|
||||||
ChevronUp,
|
ChevronUp,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
|
WrapText,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import {
|
import {
|
||||||
@ -76,6 +77,7 @@ const LogViewerContent: React.FC<{
|
|||||||
const [loadingPods, setLoadingPods] = useState(app.runtimeType === 'K8S');
|
const [loadingPods, setLoadingPods] = useState(app.runtimeType === 'K8S');
|
||||||
const [isControlBarCollapsed, setIsControlBarCollapsed] = useState(false);
|
const [isControlBarCollapsed, setIsControlBarCollapsed] = useState(false);
|
||||||
const [status, setStatus] = useState<LogStreamStatus>(LogStreamStatus.DISCONNECTED);
|
const [status, setStatus] = useState<LogStreamStatus>(LogStreamStatus.DISCONNECTED);
|
||||||
|
const [wordWrap, setWordWrap] = useState(true);
|
||||||
|
|
||||||
const controlApiRef = useRef<LogStreamControlAPI | null>(null);
|
const controlApiRef = useRef<LogStreamControlAPI | null>(null);
|
||||||
const logApiRef = useRef<LogViewerAPI | null>(null);
|
const logApiRef = useRef<LogViewerAPI | null>(null);
|
||||||
@ -392,6 +394,9 @@ const LogViewerContent: React.FC<{
|
|||||||
|
|
||||||
controlApiRef.current.send(JSON.stringify(stopMessage));
|
controlApiRef.current.send(JSON.stringify(stopMessage));
|
||||||
|
|
||||||
|
// 立即更新状态为DISCONNECTED,确保UI正确显示开始按钮
|
||||||
|
setStatus(LogStreamStatus.DISCONNECTED);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
controlApiRef.current?.disconnect();
|
controlApiRef.current?.disconnect();
|
||||||
}, 100);
|
}, 100);
|
||||||
@ -537,6 +542,20 @@ const LogViewerContent: React.FC<{
|
|||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>清空</TooltipContent>
|
<TooltipContent>清空</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant={wordWrap ? "default" : "outline"}
|
||||||
|
onClick={() => setWordWrap(!wordWrap)}
|
||||||
|
className="h-7 w-7 p-0"
|
||||||
|
>
|
||||||
|
<WrapText className="h-3 w-3" />
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>{wordWrap ? '关闭换行' : '自动换行'}</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
@ -587,6 +606,7 @@ const LogViewerContent: React.FC<{
|
|||||||
theme: 'vs-dark',
|
theme: 'vs-dark',
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
wordWrap: wordWrap,
|
||||||
}}
|
}}
|
||||||
onReady={(controlApi, logApi) => {
|
onReady={(controlApi, logApi) => {
|
||||||
controlApiRef.current = controlApi;
|
controlApiRef.current = controlApi;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user