feat: TicketCreatePage tab化 + SchemaSidebar + Redis快速搜索 + Dashboard导航修复

TicketCreatePage 重构:
- SQL编辑器右侧新增数据库浏览器面板(tab化)
- 表结构Tab: 表列表→字段展开(PK/索引标记)→点击插入SQL
- 索引Tab: 选中表的索引详情(索引名/类型/字段/基数)
- Redis Keys Tab: DB选择器+Key模式搜索+Key列表+类型/TTL/值查看

SchemaSidebar 新组件(365行):
- MySQL/PostgreSQL: 左侧数据库表树→字段→点击插入SQL
- Redis: Key树(DB选择→模式搜索→Key值查看, 类似Another Redis Desktop Manager)
- 用于 QueriesPage 查询页面

Dashboard:
- 快捷按钮改用 useNavigate + onClick 替代 <a href>

API增强:
- redis.ts: 新增 getKeys/createKey/deleteKey 方法
- instanceDetail.ts: 导出 TableMeta/TableDetail/ColumnInfo/IndexInfo 类型接口
This commit is contained in:
logan committed 2026-05-24 15:10:31 +08:00
1 parent 8471f368eb
commit 0fb947dcb5
6 files changed
+1020 -476

No files matched your search

+42 -6
View File
@@ -1,9 +1,10 @@
import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
import {
Plus, X, AlertTriangle, CheckCircle, Play, Loader2,
ChevronDown, Clock, FileText, Sparkles, Star,
StarOff, Download, Search, ArrowUpDown,
ArrowUp, ArrowDown, Eye, Hash, PanelLeftClose,
ChevronDown, ChevronRight, Clock, FileText, Sparkles, Star,
StarOff, Download, Search, ArrowUpDown, Database, Table2,
ArrowUp, ArrowDown, Eye, Hash, PanelLeftClose, Columns3,
KeyRound, FolderOpen, Server, Zap,
} from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { useActionPermission } from '@/hooks/useAuth';
@@ -12,7 +13,10 @@ import EmptyState from '@/components/EmptyState';
import { queryApi } from '@/api/query';
import { instanceApi } from '@/api/instance';
import SqlEditor from '@/components/SqlEditor';
import SchemaSidebar from '@/components/SchemaSidebar';
import { getTemplateSQL, getTemplatesForType } from '@/lib/queryTemplates';
import { instanceDetailApi, type TableMeta, type ColumnInfo } from '@/api/instanceDetail';
import { redisApi } from '@/api/redis';
import type { DBType, QueryTemplate } from '@/lib/queryTemplates';
/* ------------------------------------------------------------------ */
@@ -299,6 +303,7 @@ function NewQueryPanel({
const [rowHeight] = useState(36);
const [visibleRange, setVisibleRange] = useState({ start: 0, end: 50 });
const resultContainerRef = useRef<HTMLDivElement>(null);
const [showSidebar, setShowSidebar] = useState(true);
useEffect(() => {
instanceApi.list().then(res => {
@@ -564,6 +569,20 @@ function NewQueryPanel({
<FileText className="w-4 h-4 text-[var(--dg-text-secondary)]" />
查询语句 <span className="text-red-400">*</span>
</label>
<div className="flex items-center gap-2">
{instanceId && (
<button
onClick={() => setShowSidebar(!showSidebar)}
className={`flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-lg border transition-all ${
showSidebar
? 'bg-blue-500/15 text-blue-400 border-blue-500/30'
: 'text-[var(--dg-text-secondary)] bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] hover:bg-[var(--dg-bg-hover)]'
}`}
>
<Database className="w-3.5 h-3.5" />
{showSidebar ? '隐藏导航' : '显示导航'}
</button>
)}
<button
onClick={() => setShowTemplates(!showTemplates)}
className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium bg-[var(--dg-bg-tertiary)] hover:bg-[var(--dg-bg-hover)] border border-[var(--dg-border)] hover:border-[var(--dg-text-muted)] rounded-lg transition-all"
@@ -572,6 +591,7 @@ function NewQueryPanel({
快捷模板 ({templates.length})
<ChevronDown className={`w-3.5 h-3.5 transition-transform ${showTemplates ? 'rotate-180' : ''}`} />
</button>
</div>
</div>
{showTemplates && (
@@ -626,9 +646,23 @@ function NewQueryPanel({
</div>
)}
{/* CodeMirror Editor */}
<div className="dg-card overflow-hidden">
<SqlEditor
{/* CodeMirror Editor + Schema Sidebar */}
<div className="grid grid-cols-1 lg:grid-cols-4 gap-4">
{/* Schema Sidebar */}
{showSidebar && instanceId && (
<div className="lg:col-span-1 h-[280px]">
<SchemaSidebar
instanceId={instanceId}
database={database}
dbType={dbType}
onInsert={(text) => setSql(prev => prev + (prev.trim() ? ' ' : '') + text + ' ')}
/>
</div>
)}
{/* Editor */}
<div className={showSidebar && instanceId ? 'lg:col-span-3' : 'lg:col-span-4'}>
<div className="dg-card overflow-hidden">
<SqlEditor
value={sql}
onChange={setSql}
placeholder={placeholderMap[dbType]}
@@ -655,6 +689,8 @@ function NewQueryPanel({
</div>
</div>
</div>
</div>
</div>
</div>
{/* Security notice */}