From 528f3c51a0169e5fdf35962b5573408cdb3d45ff Mon Sep 17 00:00:00 2001 From: Syngnat Date: Fri, 19 Jun 2026 14:19:06 +0800 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(sidebar):=20?= =?UTF-8?q?=E8=BF=81=E5=87=BA=E5=91=BD=E4=BB=A4=E6=90=9C=E7=B4=A2=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E7=B1=BB=E5=9E=8B=E4=B8=8E=20shouldLoadSidebarNodeOnE?= =?UTF-8?q?xpand?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 迁出 V2CommandSearchMode/V2CommandSearchQuery 类型与 parseV2CommandSearchQuery(支持 @/?前缀切换 object/ai 模式) - 迁出 shouldLoadSidebarNodeOnExpand(节点懒加载判定) - SidebarNodeLike 加可选 key 字段以适配测试用法 - Sidebar.tsx 从 10235 减至 10187 行,sidebarHelpers.ts 增至 215 行 --- frontend/src/components/Sidebar.tsx | 64 ++-------------- .../src/components/sidebar/sidebarHelpers.ts | 73 +++++++++++++++++++ 2 files changed, 81 insertions(+), 56 deletions(-) diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 2c6dde9..5679f67 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -4,11 +4,15 @@ import { formatSidebarRowCount, hasSidebarLazyChildren, shouldClearSidebarActiveContextOnEmptySelect, + shouldLoadSidebarNodeOnExpand, getV2RailConnectionGroupBadgeText, isV2SidebarObjectNode, resolveV2ObjectGroupTitle, resolveSidebarTableNameForCopy, + parseV2CommandSearchQuery, type V2ExplorerFilter, + type V2CommandSearchMode, + type V2CommandSearchQuery, } from './sidebar/sidebarHelpers'; // 重新导出,保持外部测试文件的 `from './Sidebar'` 兼容 export { @@ -16,10 +20,12 @@ export { formatSidebarRowCount, hasSidebarLazyChildren, shouldClearSidebarActiveContextOnEmptySelect, + shouldLoadSidebarNodeOnExpand, getV2RailConnectionGroupBadgeText, isV2SidebarObjectNode, resolveV2ObjectGroupTitle, resolveSidebarTableNameForCopy, + parseV2CommandSearchQuery, } from './sidebar/sidebarHelpers'; import React, { useEffect, useState, useMemo, useRef, useCallback, useDeferredValue } from 'react'; import { createPortal } from 'react-dom'; @@ -290,17 +296,7 @@ export const SQLFileExecutionProgressContent: React.FC ); -export const shouldLoadSidebarNodeOnExpand = ( - node: Pick | null | undefined, -): boolean => { - if (!node || node.isLeaf === true || hasSidebarLazyChildren(node.children)) return false; - return node.type === 'connection' - || node.type === 'database' - || node.type === 'external-sql-root' - || node.type === 'table' - || node.type === 'jvm-mode' - || node.type === 'jvm-resource'; -}; +// shouldLoadSidebarNodeOnExpand 已迁移到 ./sidebar/sidebarHelpers // resolveSidebarTableNameForCopy 已迁移到 ./sidebar/sidebarHelpers @@ -597,51 +593,7 @@ export type V2CommandSearchItem = dbName?: string; }; -export type V2CommandSearchMode = 'default' | 'object' | 'ai'; - -export interface V2CommandSearchQuery { - mode: V2CommandSearchMode; - rawValue: string; - keyword: string; - normalizedKeyword: string; - aiPrompt: string; -} - -export const parseV2CommandSearchQuery = (value: unknown): V2CommandSearchQuery => { - const rawValue = String(value ?? ''); - const trimmedValue = rawValue.trim(); - const firstChar = trimmedValue.charAt(0); - - if (firstChar === '@' || firstChar === '@') { - const keyword = trimmedValue.slice(1).trim(); - return { - mode: 'object', - rawValue, - keyword, - normalizedKeyword: keyword.toLowerCase(), - aiPrompt: '', - }; - } - - if (firstChar === '?' || firstChar === '?') { - const aiPrompt = trimmedValue.slice(1).trim(); - return { - mode: 'ai', - rawValue, - keyword: aiPrompt, - normalizedKeyword: aiPrompt.toLowerCase(), - aiPrompt, - }; - } - - return { - mode: 'default', - rawValue, - keyword: trimmedValue, - normalizedKeyword: trimmedValue.toLowerCase(), - aiPrompt: '', - }; -}; +// V2CommandSearchMode / V2CommandSearchQuery / parseV2CommandSearchQuery 已迁移到 ./sidebar/sidebarHelpers export const resolveSidebarConnectionIdFromKey = ( key: unknown, diff --git a/frontend/src/components/sidebar/sidebarHelpers.ts b/frontend/src/components/sidebar/sidebarHelpers.ts index 966e782..a5ba099 100644 --- a/frontend/src/components/sidebar/sidebarHelpers.ts +++ b/frontend/src/components/sidebar/sidebarHelpers.ts @@ -106,6 +106,7 @@ export const isV2SidebarObjectNode = ( * 让 sidebarHelpers 不依赖 Sidebar.tsx 内部的 TreeNode 定义,避免循环依赖。 */ export interface SidebarNodeLike { + key?: string; type?: string; dataRef?: any; title?: string; @@ -140,3 +141,75 @@ export const resolveSidebarTableNameForCopy = ( ): string => { return String(node?.dataRef?.tableName || node?.dataRef?.viewName || node?.dataRef?.eventName || node?.title || '').trim(); }; + +// === 命令搜索相关类型与解析(V2 Command Search)=== + +/** 命令搜索模式:default(默认)/ object(@前缀,对象搜索)/ ai(?或?前缀,AI 提问) */ +export type V2CommandSearchMode = 'default' | 'object' | 'ai'; + +/** 命令搜索查询解析结果 */ +export interface V2CommandSearchQuery { + mode: V2CommandSearchMode; + rawValue: string; + keyword: string; + normalizedKeyword: string; + aiPrompt: string; +} + +/** + * parseV2CommandSearchQuery 解析命令搜索框的输入。 + * - "@" 或 "@" 前缀:对象搜索模式 + * - "?" 或 "?" 前缀:AI 提问模式 + * - 无前缀:默认模式 + */ +export const parseV2CommandSearchQuery = (value: unknown): V2CommandSearchQuery => { + const rawValue = String(value ?? ''); + const trimmedValue = rawValue.trim(); + const firstChar = trimmedValue.charAt(0); + + if (firstChar === '@' || firstChar === '@') { + const keyword = trimmedValue.slice(1).trim(); + return { + mode: 'object', + rawValue, + keyword, + normalizedKeyword: keyword.toLowerCase(), + aiPrompt: '', + }; + } + + if (firstChar === '?' || firstChar === '?') { + const aiPrompt = trimmedValue.slice(1).trim(); + return { + mode: 'ai', + rawValue, + keyword: aiPrompt, + normalizedKeyword: aiPrompt.toLowerCase(), + aiPrompt, + }; + } + + return { + mode: 'default', + rawValue, + keyword: trimmedValue, + normalizedKeyword: trimmedValue.toLowerCase(), + aiPrompt: '', + }; +}; + +/** + * shouldLoadSidebarNodeOnExpand 判断节点展开时是否需要懒加载子节点。 + * 仅 connection/database/external-sql-root/table/jvm-mode/jvm-resource 类型且无已加载 children 时返回 true。 + */ +export const shouldLoadSidebarNodeOnExpand = ( + node: Pick | null | undefined, +): boolean => { + if (!node || node.isLeaf === true || hasSidebarLazyChildren(node.children)) return false; + return node.type === 'connection' + || node.type === 'database' + || node.type === 'external-sql-root' + || node.type === 'table' + || node.type === 'jvm-mode' + || node.type === 'jvm-resource'; +};