♻️ refactor(sidebar): 抽出 ConnectionRail 为独立子组件

- 新建 sidebar/SidebarConnectionRail.tsx:V2 连接栏(新建分组/批量导出/SQL 文件/定位/AI/工具/设置 7 个按钮)
- Props 用聚合对象(labels + handlers + canLocateActiveTab)避免 18+ 个独立 props drilling
- Sidebar.tsx 删除 renderV2ConnectionRail(-93 行),加 v2ConnectionRailProps 构造 + <SidebarConnectionRail /> 调用
- Sidebar.tsx 从 10187 减至 10122 行
This commit is contained in:
Syngnat
2026-06-19 14:29:57 +08:00
parent 528f3c51a0
commit 2c8128724e
2 changed files with 173 additions and 94 deletions

View File

@@ -1,4 +1,5 @@
import Modal from './common/ResizableDraggableModal';
import SidebarConnectionRail from './sidebar/SidebarConnectionRail';
import {
V2_RAIL_UNGROUPED_CONNECTION_GROUP_ID,
formatSidebarRowCount,
@@ -9162,104 +9163,38 @@ const Sidebar: React.FC<{
const v2CommandSearchLabel = t('sidebar.command_search.label');
const v2CommandSearchPlaceholder = t('sidebar.command_search.placeholder');
const renderV2ConnectionRail = () => (
<div className="gn-v2-connection-rail" aria-label={v2RailSystemActionsLabel}>
<div className="gn-v2-rail-primary-actions" aria-label={v2RailObjectActionsLabel}>
<Tooltip title={v2NewGroupLabel} placement="right">
<button
type="button"
className="gn-v2-rail-tool gn-v2-rail-action"
onClick={() => { setRenameViewTarget(null); createTagForm.resetFields(); setIsCreateTagModalOpen(true); }}
aria-label={v2NewGroupLabel}
data-sidebar-create-group-action="true"
>
<FolderOpenOutlined />
</button>
</Tooltip>
<Tooltip title={v2BatchTablesLabel} placement="right">
<button
type="button"
className="gn-v2-rail-tool gn-v2-rail-action"
onClick={() => openBatchTableExportWorkbench()}
aria-label={v2BatchTablesLabel}
data-sidebar-batch-table-action="true"
>
<TableOutlined />
</button>
</Tooltip>
<Tooltip title={v2BatchDatabasesLabel} placement="right">
<button
type="button"
className="gn-v2-rail-tool gn-v2-rail-action"
onClick={() => openBatchDatabaseExportWorkbench()}
aria-label={v2BatchDatabasesLabel}
data-sidebar-batch-database-action="true"
>
<DatabaseOutlined />
</button>
</Tooltip>
<Tooltip title={v2OpenExternalSqlFileLabel} placement="right">
<button
type="button"
className="gn-v2-rail-tool gn-v2-rail-action"
onClick={handleOpenSQLFileFromToolbar}
aria-label={v2OpenExternalSqlFileLabel}
data-sidebar-open-external-sql-file-action="true"
>
<FileAddOutlined />
</button>
</Tooltip>
<Tooltip title={canLocateActiveTab ? v2LocateCurrentTableLabel : v2LocateCurrentTableUnavailableLabel} placement="right">
<span className="gn-v2-rail-action-wrap">
<button
type="button"
className="gn-v2-rail-tool gn-v2-rail-action"
onClick={handleLocateActiveTabInSidebar}
aria-label={v2LocateCurrentTableLabel}
data-sidebar-locate-current-tab-action="true"
disabled={!canLocateActiveTab}
>
<AimOutlined />
</button>
</span>
</Tooltip>
</div>
<div className="gn-v2-rail-secondary-actions" aria-label={v2RailSystemActionsLabel}>
<Tooltip title={v2AiAssistantLabel} placement="right">
<button
type="button"
className="gn-v2-rail-tool"
onClick={onToggleAI}
aria-label={v2AiAssistantLabel}
data-gonavi-ai-entry-action="true"
>
<RobotOutlined />
</button>
</Tooltip>
<Tooltip title={v2ToolsLabel} placement="right">
<button
type="button"
className="gn-v2-rail-tool"
onClick={onOpenTools}
aria-label={v2ToolsLabel}
data-gonavi-open-tools-action="true"
>
<ToolOutlined />
</button>
</Tooltip>
<Tooltip title={v2SettingsLabel} placement="right">
<button type="button" className="gn-v2-rail-tool" onClick={onOpenSettings} aria-label={v2SettingsLabel}>
<SettingOutlined />
</button>
</Tooltip>
</div>
</div>
);
// V2 Connection Rail 子组件 props从原 renderV2ConnectionRail 抽出,保留所有原行为)
const v2ConnectionRailProps = {
labels: {
railSystemActions: v2RailSystemActionsLabel,
railObjectActions: v2RailObjectActionsLabel,
newGroup: v2NewGroupLabel,
batchTables: v2BatchTablesLabel,
batchDatabases: v2BatchDatabasesLabel,
openExternalSqlFile: v2OpenExternalSqlFileLabel,
locateCurrentTable: v2LocateCurrentTableLabel,
locateCurrentTableUnavailable: v2LocateCurrentTableUnavailableLabel,
aiAssistant: v2AiAssistantLabel,
tools: v2ToolsLabel,
settings: v2SettingsLabel,
},
handlers: {
openCreateTagModal: () => { setRenameViewTarget(null); createTagForm.resetFields(); setIsCreateTagModalOpen(true); },
openBatchTableExport: () => openBatchTableExportWorkbench(),
openBatchDatabaseExport: () => openBatchDatabaseExportWorkbench(),
openExternalSqlFile: handleOpenSQLFileFromToolbar,
locateActiveTab: handleLocateActiveTabInSidebar,
toggleAI: onToggleAI ?? (() => {}),
openTools: onOpenTools ?? (() => {}),
openSettings: onOpenSettings ?? (() => {}),
},
canLocateActiveTab,
};
return (
<div className={isV2Ui ? 'gn-v2-sidebar-redesign' : undefined} style={{ display: 'flex', height: '100%', minHeight: 0 }}>
{exportProgressModal}
{isV2Ui && renderV2ConnectionRail()}
{isV2Ui && <SidebarConnectionRail {...v2ConnectionRailProps} />}
<div className={isV2Ui ? 'gn-v2-object-explorer' : undefined} style={{ display: 'flex', flexDirection: 'column', height: '100%', minWidth: 0, flex: 1 }}>
{isV2Ui && (
<div className="gn-v2-active-connection-header" data-object-count={activeConnectionObjectCount}>

View File

@@ -0,0 +1,144 @@
import React from 'react';
import { Tooltip, Form } from 'antd';
import {
FolderOpenOutlined,
TableOutlined,
DatabaseOutlined,
FileAddOutlined,
AimOutlined,
RobotOutlined,
ToolOutlined,
SettingOutlined,
} from '@ant-design/icons';
// V2 Connection Rail 子组件(从 Sidebar.tsx 抽取)。
//
// 注意:本组件是 Sidebar.tsx 拆分的一部分,依赖大量主组件的 label/state/handler。
// 通过聚合 props 对象传递,避免 18+ 个独立 props 的 drilling 噪音。
// 后续状态管理重构PR-A会把 labels/handlers 迁到 useSidebarUIState hook。
//
// 设计取舍:用 labels + handlers 聚合对象 + FormInstance换取 Sidebar.tsx 减少 ~100 行。
// 主组件 props drilling 复杂度可控(只有一处调用点)。
export interface SidebarConnectionRailProps {
labels: {
railSystemActions: string;
railObjectActions: string;
newGroup: string;
batchTables: string;
batchDatabases: string;
openExternalSqlFile: string;
locateCurrentTable: string;
locateCurrentTableUnavailable: string;
aiAssistant: string;
tools: string;
settings: string;
};
handlers: {
openCreateTagModal: () => void;
openBatchTableExport: () => void;
openBatchDatabaseExport: () => void;
openExternalSqlFile: () => void;
locateActiveTab: () => void;
toggleAI: () => void;
openTools: () => void;
openSettings: () => void;
};
canLocateActiveTab: boolean;
}
const SidebarConnectionRail: React.FC<SidebarConnectionRailProps> = ({ labels, handlers, canLocateActiveTab }) => (
<div className="gn-v2-connection-rail" aria-label={labels.railSystemActions}>
<div className="gn-v2-rail-primary-actions" aria-label={labels.railObjectActions}>
<Tooltip title={labels.newGroup} placement="right">
<button
type="button"
className="gn-v2-rail-tool gn-v2-rail-action"
onClick={handlers.openCreateTagModal}
aria-label={labels.newGroup}
data-sidebar-create-group-action="true"
>
<FolderOpenOutlined />
</button>
</Tooltip>
<Tooltip title={labels.batchTables} placement="right">
<button
type="button"
className="gn-v2-rail-tool gn-v2-rail-action"
onClick={handlers.openBatchTableExport}
aria-label={labels.batchTables}
data-sidebar-batch-table-action="true"
>
<TableOutlined />
</button>
</Tooltip>
<Tooltip title={labels.batchDatabases} placement="right">
<button
type="button"
className="gn-v2-rail-tool gn-v2-rail-action"
onClick={handlers.openBatchDatabaseExport}
aria-label={labels.batchDatabases}
data-sidebar-batch-database-action="true"
>
<DatabaseOutlined />
</button>
</Tooltip>
<Tooltip title={labels.openExternalSqlFile} placement="right">
<button
type="button"
className="gn-v2-rail-tool gn-v2-rail-action"
onClick={handlers.openExternalSqlFile}
aria-label={labels.openExternalSqlFile}
data-sidebar-open-external-sql-file-action="true"
>
<FileAddOutlined />
</button>
</Tooltip>
<Tooltip title={canLocateActiveTab ? labels.locateCurrentTable : labels.locateCurrentTableUnavailable} placement="right">
<span className="gn-v2-rail-action-wrap">
<button
type="button"
className="gn-v2-rail-tool gn-v2-rail-action"
onClick={handlers.locateActiveTab}
aria-label={labels.locateCurrentTable}
data-sidebar-locate-current-tab-action="true"
disabled={!canLocateActiveTab}
>
<AimOutlined />
</button>
</span>
</Tooltip>
</div>
<div className="gn-v2-rail-secondary-actions" aria-label={labels.railSystemActions}>
<Tooltip title={labels.aiAssistant} placement="right">
<button
type="button"
className="gn-v2-rail-tool"
onClick={handlers.toggleAI}
aria-label={labels.aiAssistant}
data-gonavi-ai-entry-action="true"
>
<RobotOutlined />
</button>
</Tooltip>
<Tooltip title={labels.tools} placement="right">
<button
type="button"
className="gn-v2-rail-tool"
onClick={handlers.openTools}
aria-label={labels.tools}
data-gonavi-open-tools-action="true"
>
<ToolOutlined />
</button>
</Tooltip>
<Tooltip title={labels.settings} placement="right">
<button type="button" className="gn-v2-rail-tool" onClick={handlers.openSettings} aria-label={labels.settings}>
<SettingOutlined />
</button>
</Tooltip>
</div>
</div>
);
export default SidebarConnectionRail;