同步完整源码至远程:扁平化重构现状 + 未入库源文件

- 补入库:server/internal/db/dump.go、redis 分页/扫描预算测试、opsxdb-mcp main_test、
  packages/opsxdb-mcp package-lock、docs 审计与对比文档等 37 个新文件
- 含结构扁平化进行中的 80 处修改与 155 处旧结构删除(server/ src/ src-tauri/ 为当前有效源)
- 构建产物(bin/target/dist)与签名私钥仍按规则排除
This commit is contained in:
logan committed 2026-10-16 03:47:33 +08:00
1 parent 5c0be49217
commit 2c0bfafd8d
269 files changed
+10372 -16435

No files matched your search

+60 -52
View File
@@ -1,10 +1,12 @@
import { useEffect, useMemo, useRef, useState } from "react";
import { closeSession } from "./api";
import { closeSession, openSession } from "./api";
import { driverById } from "./catalog";
import { askInput } from "./dialogs";
import { DriverIcon } from "./DriverIcon";
import { ObjectTree } from "./ObjectTree";
import { ContextMenu } from "./ContextMenu";
import { TreeChevron } from "./TreeChevron";
import { connectionEndpoint, connectionUri } from "./contextActions";
import {
DEFAULT_CONN_GROUP,
useWorkspaceStore,
@@ -34,7 +36,10 @@ export function ConnectionSidebar({
const moveConnection = useWorkspaceStore((s) => s.moveConnection);
const toggleConnGroup = useWorkspaceStore((s) => s.toggleConnGroup);
const notify = useWorkspaceStore((s) => s.notify);
const notifyError = useWorkspaceStore((s) => s.notifyError);
const editConnection = useWorkspaceStore((s) => s.editConnection);
const connState = useWorkspaceStore((s) => s.connState);
const set = useWorkspaceStore((s) => s.set);
const [ctxMenu, setCtxMenu] = useState<{ x: number; y: number; conn: SavedConnection } | null>(null);
/** 断开连接:关会话 + 清树 + 清激活 */
@@ -51,6 +56,26 @@ export function ConnectionSidebar({
st.set("connState", "down");
st.set("status", `已断开 ${c.name}`);
}
notify({ kind: "warning", title: "已断开", message: c.name, mode: "toast", durationMs: 1800 });
};
const reconnect = async (c: SavedConnection) => {
set("connState", "reconnecting");
set("status", "重连中…");
try {
useWorkspaceStore.getState().setSession(c.id, null);
const { sessionId } = await openSession(c);
useWorkspaceStore.getState().setSession(c.id, sessionId);
useWorkspaceStore.getState().selectConnection(c.id);
set("connState", "ok");
set("status", `已重连 ${c.name}` + (c.database ? ` · ${c.database}` : ""));
notify({ kind: "success", title: "重连成功", message: c.name, mode: "toast", durationMs: 1600 });
} catch (e) {
set("connState", "down");
const msg = e instanceof Error ? e.message : String(e);
set("status", `重连失败:${msg}`);
notifyError(e, "modal");
}
};
const [dragId, setDragId] = useState<string | null>(null);
@@ -122,7 +147,7 @@ export function ConnectionSidebar({
};
return (
<div className="flex shrink-0 flex-col">
<div className="flex min-h-0 flex-1 flex-col overflow-hidden">
<div className="flex items-center justify-between px-1.5 py-1 text-[11px]" style={{ color: "var(--ops-muted)" }}>
<span>连接</span>
<button type="button" className="hover:underline" style={{ color: "var(--ops-accent)" }} onClick={onAddGroup} title="新建分组">
@@ -255,16 +280,36 @@ export function ConnectionSidebar({
<span className="h-3 w-1 shrink-0 rounded-sm" style={{ background: c.color }} />
)}
<DriverIcon driver={c.driver} size={14} />
<span className="min-w-0 truncate" title={`${driverById(c.driver)?.name ?? c.driver} · ${c.name}`}>
{c.name}
<span className="min-w-0 flex-1 truncate" title={`${driverById(c.driver)?.name ?? c.driver} · ${c.name} · ${connectionEndpoint(c)}`}>
<span className="truncate">{c.name}</span>
{(c.host || c.redisNodes || c.database) && (
<span className="ml-1 text-[10px] opacity-45">
{c.host || c.redisNodes ? connectionEndpoint(c) : c.database}
</span>
)}
</span>
<span
className="ml-1 h-1.5 w-1.5 shrink-0 rounded-full"
style={{
background: activeId === c.id ? '#22c55e' : 'var(--ops-muted)',
background:
activeId === c.id
? connState === "down"
? "var(--ops-danger)"
: connState === "reconnecting"
? "var(--ops-warning)"
: "#22c55e"
: "var(--ops-muted)",
opacity: activeId === c.id ? 1 : 0.4,
}}
title={activeId === c.id ? '已连接' : '未激活'}
title={
activeId === c.id
? connState === "down"
? "已断开"
: connState === "reconnecting"
? "重连中…"
: "已连接"
: "未激活"
}
/>
</button>
<button
@@ -298,52 +343,15 @@ export function ConnectionSidebar({
})}
</div>
{ctxMenu && (
<div
className="ops-ctx"
style={{ position: "fixed", left: ctxMenu.x, top: ctxMenu.y, zIndex: 1000 }}
>
{activeId === ctxMenu.conn.id && (
<button
type="button"
onClick={() => {
disconnect(ctxMenu.conn);
setCtxMenu(null);
}}
>
断开连接
</button>
)}
<button
type="button"
onClick={() => {
onSelect(ctxMenu.conn.id);
setCtxMenu(null);
}}
>
连接
</button>
<button
type="button"
onClick={() => {
editConnection(ctxMenu.conn);
setCtxMenu(null);
}}
>
编辑
</button>
<button
type="button"
style={{ color: "var(--ops-danger)" }}
onClick={() => {
onDelete(ctxMenu.conn.id);
setCtxMenu(null);
}}
>
删除
</button>
</div>
)}
{ctxMenu && <ContextMenu x={ctxMenu.x} y={ctxMenu.y} title={ctxMenu.conn.name} onClose={() => setCtxMenu(null)} items={[
{ label: "连接", hidden: activeId === ctxMenu.conn.id, action: () => onSelect(ctxMenu.conn.id) },
{ label: "断开连接", hidden: activeId !== ctxMenu.conn.id, action: () => disconnect(ctxMenu.conn) },
{ label: "重新连接", action: () => void reconnect(ctxMenu.conn) },
{ label: "编辑连接…", action: () => editConnection(ctxMenu.conn) },
{ label: "复制连接地址(无凭据)", separator: true, action: () => { void navigator.clipboard.writeText(connectionUri(ctxMenu.conn)).catch((e) => notifyError(e, "toast")); } },
{ label: "复制主机端口", action: () => { void navigator.clipboard.writeText(connectionEndpoint(ctxMenu.conn)).catch((e) => notifyError(e, "toast")); } },
{ label: "删除连接…", separator: true, danger: true, action: () => onDelete(ctxMenu.conn.id) },
]} />}
</div>
);
}