mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-02 04:29:38 +08:00
- queryWithContext 中 find/count 命令改用原生 Collection.Find()和 CountDocuments() API,替代RunCommand 的 firstBatch 模式
- 新增 convertBsonValue 将 ObjectID/bson.M/bson.D/bson.A 转为JSON 友好类型,_id 列自动置首
- DBQuery 增加 MongoDB JSON 命令识别,避免 find 命令误走 Exec 分支
⚡️perf(macos): 动态控制 NSVisualEffectView 降低 MacOS GPU 持续消耗,Windows不受影响
- NSVisualEffectView 启动默认 alpha 由 0.72 改为 0,窗口默认 opaque
- 新增 gonaviSetEffectViewAlpha ObjC 函数支持运行时动态切换
- 新增 SetWindowTranslucency Wails 绑定方法供前端调用
- 启动重试次数由 24 次缩减至 8 次
- opacity=1.0 且 blur=0 时窗口标记 opaque,GPU 不再持续计算模糊合成
- App.tsx 仅保留最外层 Layout 的 backdropFilter,移除 TitleBar/MenuBar/Content/DataGrid/LogPanel 冗余嵌套
- App.css 移除暗色模式全局 text-shadow 减少 compositing 开销
132 lines
4.8 KiB
TypeScript
132 lines
4.8 KiB
TypeScript
import React, { useRef, useEffect } from 'react';
|
|
import { Table, Tag, Button, Tooltip } from 'antd';
|
|
import { ClearOutlined, CloseOutlined, CaretRightOutlined, BugOutlined } from '@ant-design/icons';
|
|
import { useStore } from '../store';
|
|
import { normalizeOpacityForPlatform } from '../utils/appearance';
|
|
|
|
interface LogPanelProps {
|
|
height: number;
|
|
onClose: () => void;
|
|
onResizeStart: (e: React.MouseEvent) => void;
|
|
}
|
|
|
|
const LogPanel: React.FC<LogPanelProps> = ({ height, onClose, onResizeStart }) => {
|
|
const sqlLogs = useStore(state => state.sqlLogs);
|
|
const clearSqlLogs = useStore(state => state.clearSqlLogs);
|
|
const theme = useStore(state => state.theme);
|
|
const appearance = useStore(state => state.appearance);
|
|
const darkMode = theme === 'dark';
|
|
const opacity = normalizeOpacityForPlatform(appearance.opacity);
|
|
|
|
// Background Helper
|
|
const getBg = (darkHex: string) => {
|
|
if (!darkMode) return `rgba(255, 255, 255, ${opacity})`;
|
|
const hex = darkHex.replace('#', '');
|
|
const r = parseInt(hex.substring(0, 2), 16);
|
|
const g = parseInt(hex.substring(2, 4), 16);
|
|
const b = parseInt(hex.substring(4, 6), 16);
|
|
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
|
};
|
|
const bgMain = getBg('#1f1f1f');
|
|
const bgToolbar = getBg('#2a2a2a');
|
|
|
|
const columns = [
|
|
{
|
|
title: 'Time',
|
|
dataIndex: 'timestamp',
|
|
width: 80,
|
|
render: (ts: number) => <span style={{ color: '#888', fontSize: '12px' }}>{new Date(ts).toLocaleTimeString()}</span>
|
|
},
|
|
{
|
|
title: 'Status',
|
|
dataIndex: 'status',
|
|
width: 70,
|
|
render: (status: string) => (
|
|
<Tag color={status === 'success' ? 'success' : 'error'} style={{ marginRight: 0 }}>
|
|
{status === 'success' ? 'OK' : 'ERR'}
|
|
</Tag>
|
|
)
|
|
},
|
|
{
|
|
title: 'Duration',
|
|
dataIndex: 'duration',
|
|
width: 70,
|
|
render: (d: number) => <span style={{ color: d > 1000 ? 'orange' : 'inherit', fontSize: '12px' }}>{d}ms</span>
|
|
},
|
|
{
|
|
title: 'SQL / Message',
|
|
dataIndex: 'sql',
|
|
render: (text: string, record: any) => (
|
|
<div style={{ fontFamily: 'monospace', wordBreak: 'break-all', fontSize: '12px', lineHeight: '1.2' }}>
|
|
<div style={{ color: darkMode ? '#a6e22e' : '#005cc5' }}>{text}</div>
|
|
{record.message && <div style={{ color: '#ff4d4f', marginTop: 2 }}>{record.message}</div>}
|
|
{record.affectedRows !== undefined && <div style={{ color: '#888', marginTop: 1 }}>Affected: {record.affectedRows}</div>}
|
|
</div>
|
|
)
|
|
}
|
|
];
|
|
|
|
return (
|
|
<div style={{
|
|
height,
|
|
borderTop: 'none',
|
|
background: bgMain,
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
position: 'relative',
|
|
zIndex: 100 // Ensure above other content
|
|
}}>
|
|
{/* Resize Handle */}
|
|
<div
|
|
onMouseDown={onResizeStart}
|
|
style={{
|
|
position: 'absolute',
|
|
top: -4,
|
|
left: 0,
|
|
right: 0,
|
|
height: 8,
|
|
cursor: 'row-resize',
|
|
zIndex: 10
|
|
}}
|
|
/>
|
|
|
|
{/* Toolbar */}
|
|
<div style={{
|
|
padding: '4px 8px',
|
|
borderBottom: 'none',
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
height: 32
|
|
}}>
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8, fontWeight: 'bold', fontSize: '12px' }}>
|
|
<BugOutlined /> SQL 执行日志
|
|
</div>
|
|
<div>
|
|
<Tooltip title="清空日志">
|
|
<Button type="text" size="small" icon={<ClearOutlined />} onClick={clearSqlLogs} />
|
|
</Tooltip>
|
|
<Tooltip title="关闭面板">
|
|
<Button type="text" size="small" icon={<CloseOutlined />} onClick={onClose} />
|
|
</Tooltip>
|
|
</div>
|
|
</div>
|
|
|
|
{/* List */}
|
|
<div style={{ flex: 1, overflow: 'auto' }}>
|
|
<Table
|
|
dataSource={sqlLogs}
|
|
columns={columns}
|
|
size="small"
|
|
pagination={false}
|
|
rowKey="id"
|
|
showHeader={false}
|
|
// scroll={{ y: height - 32 }} // Let flex handle it
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default LogPanel;
|