mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-04 04:47:49 +08:00
♻️ refactor(sidebar): 清理 V2 rail 残留死代码
- 删除未被调用的 rail connection button/group 渲染闭包 - 移除对应的折叠、拖拽状态和 badge/host 辅助函数 - 保留当前可达的 active connection 状态展示和树拖拽排序逻辑
This commit is contained in:
@@ -46,7 +46,6 @@ import { Tree, message, Dropdown, MenuProps, Input, Button, Form, Badge, Checkbo
|
||||
FolderAddOutlined,
|
||||
SaveOutlined,
|
||||
EditOutlined,
|
||||
DownOutlined,
|
||||
SearchOutlined,
|
||||
KeyOutlined,
|
||||
ThunderboltOutlined,
|
||||
@@ -1190,18 +1189,6 @@ const Sidebar: React.FC<{
|
||||
const allSavedQueriesNode = useMemo<TreeNode | null>(() => {
|
||||
return buildAllSavedQueriesTreeNode(savedQueries, connections);
|
||||
}, [connections, savedQueries]);
|
||||
const v2RailConnectionGroups = useMemo(
|
||||
() => buildV2RailConnectionGroups(connections, connectionTags, sidebarRootOrder),
|
||||
[connections, connectionTags, sidebarRootOrder],
|
||||
);
|
||||
const [collapsedV2RailGroupIds, setCollapsedV2RailGroupIds] = useState<string[]>([]);
|
||||
const collapsedV2RailGroupIdSet = useMemo(
|
||||
() => new Set(collapsedV2RailGroupIds),
|
||||
[collapsedV2RailGroupIds],
|
||||
);
|
||||
const hasV2RailConnectionGroups = v2RailConnectionGroups.some((group) => !group.isUngrouped);
|
||||
const [draggingV2RailRootToken, setDraggingV2RailRootToken] = useState('');
|
||||
|
||||
const snapshotTreeSelectionBeforeDrag = useCallback(() => {
|
||||
treeDragSelectionSnapshotRef.current = {
|
||||
selectedKeys: [...selectedKeys],
|
||||
@@ -6828,101 +6815,6 @@ const Sidebar: React.FC<{
|
||||
return connectionStatusMap.get(connectionId) || 'idle';
|
||||
}, [connectionStatusMap]);
|
||||
|
||||
const toggleV2RailConnectionGroup = useCallback((groupId: string) => {
|
||||
setCollapsedV2RailGroupIds((prev) => (
|
||||
prev.includes(groupId)
|
||||
? prev.filter((id) => id !== groupId)
|
||||
: [...prev, groupId]
|
||||
));
|
||||
}, []);
|
||||
|
||||
const handleV2RailRootDrop = useCallback((
|
||||
sourceToken: string,
|
||||
targetToken: string,
|
||||
insertBefore: boolean,
|
||||
) => {
|
||||
if (!sourceToken || !targetToken || sourceToken === targetToken) {
|
||||
return;
|
||||
}
|
||||
reorderSidebarRoot(sourceToken, targetToken, insertBefore);
|
||||
}, [reorderSidebarRoot]);
|
||||
|
||||
const getRailConnectionTypeLabel = (conn: SavedConnection): string => {
|
||||
const iconType = resolveConnectionIconType(conn);
|
||||
if (iconType === 'mysql' || iconType === 'mariadb' || iconType === 'oceanbase') return 'MY';
|
||||
if (iconType === 'postgres') return 'PG';
|
||||
if (iconType === 'gaussdb') return 'GS';
|
||||
if (iconType === 'redis') return 'R';
|
||||
if (iconType === 'mongodb') return 'MO';
|
||||
if (iconType === 'oracle') return 'OR';
|
||||
if (iconType === 'sqlserver') return 'SS';
|
||||
if (iconType === 'starrocks') return 'SR';
|
||||
if (iconType === 'sqlite') return 'SQ';
|
||||
if (iconType === 'jvm') return 'JV';
|
||||
return iconType.slice(0, 2).toUpperCase() || 'DB';
|
||||
};
|
||||
|
||||
const getRailConnectionHostLabel = (conn: SavedConnection): string => {
|
||||
const hostTokens = resolveConnectionHostTokens(conn.config);
|
||||
const primaryHost = String(hostTokens[0] || '').trim().replace(/^\[|\]$/g, '');
|
||||
if (primaryHost) {
|
||||
if (/^(localhost|127(?:\.\d{1,3}){3}|0\.0\.0\.0)$/i.test(primaryHost)) {
|
||||
return 'LO';
|
||||
}
|
||||
if (/^\d{1,3}(?:\.\d{1,3}){3}$/.test(primaryHost)) {
|
||||
const lastSegment = primaryHost.split('.').pop() || '';
|
||||
return lastSegment.slice(-3).toUpperCase() || 'IP';
|
||||
}
|
||||
if (primaryHost.includes(':') && /^[a-f0-9:]+$/i.test(primaryHost)) {
|
||||
const lastSegment = primaryHost.split(':').filter(Boolean).pop() || '';
|
||||
return lastSegment.slice(-3).toUpperCase() || 'IP';
|
||||
}
|
||||
|
||||
const hostFragments = primaryHost
|
||||
.split(/[^a-z0-9\u4e00-\u9fa5]+/i)
|
||||
.map((entry) => entry.trim())
|
||||
.filter(Boolean);
|
||||
if (hostFragments.length >= 2) {
|
||||
return `${hostFragments[0][0] || ''}${hostFragments[1][0] || ''}`.toUpperCase();
|
||||
}
|
||||
const hostToken = hostFragments[0] || primaryHost.split('.')[0] || '';
|
||||
if (hostToken) {
|
||||
return hostToken.replace(/[^a-z0-9\u4e00-\u9fa5]/gi, '').slice(0, 3).toUpperCase() || 'DB';
|
||||
}
|
||||
}
|
||||
|
||||
return getRailConnectionTypeLabel(conn);
|
||||
};
|
||||
|
||||
const getRailConnectionBadgeLabel = (conn: SavedConnection): string => {
|
||||
const connectionName = String(conn.name || '').trim();
|
||||
const cjkParts = connectionName.match(/[\u4e00-\u9fa5]/g);
|
||||
if (cjkParts && cjkParts.length > 0) {
|
||||
return cjkParts.slice(0, 2).join('');
|
||||
}
|
||||
|
||||
const latinTokens = connectionName.match(/[a-z0-9]+/gi) || [];
|
||||
if (latinTokens.length >= 2) {
|
||||
const firstToken = latinTokens[0] || '';
|
||||
const secondToken = latinTokens[1] || '';
|
||||
return `${firstToken[0] || ''}${secondToken[0] || ''}`.toUpperCase();
|
||||
}
|
||||
if (latinTokens.length === 1) {
|
||||
const token = latinTokens[0];
|
||||
const alphaPrefix = token.match(/^[a-z]+/i)?.[0] || '';
|
||||
if (alphaPrefix) {
|
||||
return alphaPrefix.slice(0, 3).toUpperCase();
|
||||
}
|
||||
const trailingDigits = token.match(/(\d{2,})$/)?.[1];
|
||||
if (trailingDigits) {
|
||||
return trailingDigits.slice(-3).toUpperCase();
|
||||
}
|
||||
return token.slice(0, 3).toUpperCase();
|
||||
}
|
||||
|
||||
return getRailConnectionTypeLabel(conn);
|
||||
};
|
||||
|
||||
const openV2ConnectionContextMenu = (
|
||||
event: React.MouseEvent,
|
||||
connOrNode: SavedConnection | TreeNode,
|
||||
@@ -8893,165 +8785,6 @@ const Sidebar: React.FC<{
|
||||
}
|
||||
};
|
||||
|
||||
const renderV2RailConnectionButton = (conn: SavedConnection) => {
|
||||
const accent = resolveConnectionAccentColor(conn);
|
||||
const status = buildRailConnectionStatus(conn.id);
|
||||
const badgeLabel = getRailConnectionBadgeLabel(conn);
|
||||
const hostLabel = getRailConnectionHostLabel(conn);
|
||||
const title = `${conn.name} · ${resolveConnectionHostSummary(conn.config) || conn.config.type}`;
|
||||
const rootToken = buildSidebarRootConnectionToken(conn.id);
|
||||
|
||||
return (
|
||||
<Tooltip key={conn.id} title={title} placement="right">
|
||||
<button
|
||||
type="button"
|
||||
className={`gn-v2-rail-item${conn.id === activeConnectionId ? ' is-active' : ''}`}
|
||||
draggable
|
||||
onDragStart={(event) => {
|
||||
snapshotTreeSelectionBeforeDrag();
|
||||
treeDragSelectSuppressUntilRef.current = Date.now() + 600;
|
||||
setDraggingV2RailRootToken(rootToken);
|
||||
setIsTreeDragging(true);
|
||||
event.dataTransfer.effectAllowed = 'move';
|
||||
event.dataTransfer.setData('text/plain', rootToken);
|
||||
}}
|
||||
onDragEnd={() => {
|
||||
restoreTreeSelectionAfterDrag();
|
||||
setDraggingV2RailRootToken('');
|
||||
setIsTreeDragging(false);
|
||||
}}
|
||||
onDragOver={(event) => {
|
||||
if (!draggingV2RailRootToken || draggingV2RailRootToken === rootToken) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.dataTransfer.dropEffect = 'move';
|
||||
}}
|
||||
onDrop={(event) => {
|
||||
if (!draggingV2RailRootToken || draggingV2RailRootToken === rootToken) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const rect = event.currentTarget.getBoundingClientRect();
|
||||
const insertBefore = event.clientY < rect.top + rect.height / 2;
|
||||
handleV2RailRootDrop(draggingV2RailRootToken, rootToken, insertBefore);
|
||||
restoreTreeSelectionAfterDrag();
|
||||
setDraggingV2RailRootToken('');
|
||||
setIsTreeDragging(false);
|
||||
}}
|
||||
onClick={() => selectConnectionFromRail(conn)}
|
||||
onContextMenu={(event) => openV2ConnectionContextMenu(event, conn)}
|
||||
aria-label={`切换到连接 ${conn.name}`}
|
||||
title={title}
|
||||
data-v2-rail-host-context-menu-trigger="true"
|
||||
>
|
||||
<span className="gn-v2-rail-active-bar" />
|
||||
<span className="gn-v2-rail-badge-wrap">
|
||||
<span className="gn-v2-rail-badge" style={{ background: accent }}>
|
||||
{badgeLabel}
|
||||
</span>
|
||||
<span className={`gn-v2-rail-status is-${status}`} />
|
||||
</span>
|
||||
<span className="gn-v2-rail-fallback">{hostLabel}</span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
const renderV2RailConnectionGroup = (group: V2RailConnectionGroup) => {
|
||||
const collapsed = collapsedV2RailGroupIdSet.has(group.id);
|
||||
const groupTitle = group.name || t('connection.sidebar.group.untitled');
|
||||
const rootToken = group.rootToken;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={group.id}
|
||||
className={`gn-v2-rail-group${group.isUngrouped ? ' is-ungrouped' : ''}${collapsed ? ' is-collapsed' : ''}`}
|
||||
data-v2-rail-connection-group="true"
|
||||
draggable
|
||||
onDragStart={(event) => {
|
||||
snapshotTreeSelectionBeforeDrag();
|
||||
treeDragSelectSuppressUntilRef.current = Date.now() + 600;
|
||||
setDraggingV2RailRootToken(rootToken);
|
||||
setIsTreeDragging(true);
|
||||
event.dataTransfer.effectAllowed = 'move';
|
||||
event.dataTransfer.setData('text/plain', rootToken);
|
||||
}}
|
||||
onDragEnd={() => {
|
||||
restoreTreeSelectionAfterDrag();
|
||||
setDraggingV2RailRootToken('');
|
||||
setIsTreeDragging(false);
|
||||
}}
|
||||
onDragOver={(event) => {
|
||||
if (!draggingV2RailRootToken || draggingV2RailRootToken === rootToken) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.dataTransfer.dropEffect = 'move';
|
||||
}}
|
||||
onDrop={(event) => {
|
||||
if (!draggingV2RailRootToken || draggingV2RailRootToken === rootToken) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const rect = event.currentTarget.getBoundingClientRect();
|
||||
const insertBefore = event.clientY < rect.top + rect.height / 2;
|
||||
handleV2RailRootDrop(draggingV2RailRootToken, rootToken, insertBefore);
|
||||
restoreTreeSelectionAfterDrag();
|
||||
setDraggingV2RailRootToken('');
|
||||
setIsTreeDragging(false);
|
||||
}}
|
||||
>
|
||||
{hasV2RailConnectionGroups && (
|
||||
<Tooltip title={t('connection.sidebar.group.meta', { count: group.connections.length.toLocaleString() })} placement="right">
|
||||
<button
|
||||
type="button"
|
||||
className={`gn-v2-rail-group-header${group.isUngrouped ? ' is-ungrouped' : ''}`}
|
||||
onClick={() => toggleV2RailConnectionGroup(group.id)}
|
||||
onContextMenu={(event) => {
|
||||
if (group.isUngrouped) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const position = resolveSidebarContextMenuPosition(event.clientX, event.clientY);
|
||||
setContextMenu({
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
sourceX: event.clientX,
|
||||
sourceY: event.clientY,
|
||||
items: [],
|
||||
kind: 'v2-connection-group',
|
||||
node: group,
|
||||
rootClassName: 'gn-v2-table-context-menu-popup',
|
||||
overlayStyle: { width: 264, maxWidth: 'calc(100vw - 24px)' },
|
||||
maxHeight: position.maxHeight,
|
||||
});
|
||||
}}
|
||||
aria-label={t(collapsed ? 'connection.sidebar.group.expandAria' : 'connection.sidebar.group.collapseAria', { name: groupTitle })}
|
||||
aria-expanded={!collapsed}
|
||||
title={t('connection.sidebar.group.meta', { count: group.connections.length.toLocaleString() })}
|
||||
data-v2-rail-connection-group-header="true"
|
||||
>
|
||||
<span className="gn-v2-rail-group-chevron">
|
||||
<DownOutlined />
|
||||
</span>
|
||||
<span className="gn-v2-rail-group-title">{groupTitle}</span>
|
||||
<span className="gn-v2-rail-group-count">{group.connections.length}</span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{!collapsed && (
|
||||
<div className="gn-v2-rail-group-items">
|
||||
{group.connections.map(renderV2RailConnectionButton)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const v2RailObjectActionsLabel = t('sidebar.rail.object_actions');
|
||||
const v2RailSystemActionsLabel = t('sidebar.rail.system_actions');
|
||||
const v2NewGroupLabel = t('sidebar.action.new_group');
|
||||
|
||||
Reference in New Issue
Block a user