mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-14 02:19:58 +08:00
♻️ refactor(connection): 拆分连接类型目录配置
- 抽出连接类型分组、默认端口和提示文案到独立 catalog - ConnectionModal 仅负责渲染数据源图标和选择流程 - 补充 catalog 单元测试并更新连接弹窗源码快照测试
This commit is contained in:
@@ -4,7 +4,8 @@ import { readFileSync } from 'node:fs';
|
||||
const connectionModalSource = readFileSync(new URL('./ConnectionModal.tsx', import.meta.url), 'utf8');
|
||||
const redisSectionsSource = readFileSync(new URL('./ConnectionModalRedisSections.tsx', import.meta.url), 'utf8');
|
||||
const mongoSectionsSource = readFileSync(new URL('./ConnectionModalMongoSections.tsx', import.meta.url), 'utf8');
|
||||
const source = `${connectionModalSource}\n${redisSectionsSource}\n${mongoSectionsSource}`;
|
||||
const connectionTypeCatalogSource = readFileSync(new URL('../utils/connectionTypeCatalog.ts', import.meta.url), 'utf8');
|
||||
const source = `${connectionModalSource}\n${redisSectionsSource}\n${mongoSectionsSource}\n${connectionTypeCatalogSource}`;
|
||||
|
||||
describe('ConnectionModal edit password behavior', () => {
|
||||
it('keeps the prefilled primary password masked by default', () => {
|
||||
@@ -22,14 +23,14 @@ describe('ConnectionModal edit password behavior', () => {
|
||||
|
||||
describe('ConnectionModal data source registry', () => {
|
||||
it('exposes Elasticsearch in the create-connection picker with HTTP defaults', () => {
|
||||
expect(source).toContain('case "elasticsearch":');
|
||||
expect(source).toContain("case 'elasticsearch':");
|
||||
expect(source).toContain('return 9200;');
|
||||
expect(source).toContain('elasticsearch: ["http", "https"]');
|
||||
expect(source).toContain('key: "elasticsearch"');
|
||||
expect(source).toContain('name: "Elasticsearch"');
|
||||
expect(source).toContain('getDbIcon("elasticsearch", undefined, 36)');
|
||||
expect(source).toContain("key: 'elasticsearch'");
|
||||
expect(source).toContain("name: 'Elasticsearch'");
|
||||
expect(source).toContain('icon: getDbIcon(item.key, undefined, 36)');
|
||||
expect(source).toContain('type === "elasticsearch"');
|
||||
expect(source).toContain('return "支持索引浏览、Mapping 检查、JSON DSL 和 query_string 查询";');
|
||||
expect(source).toContain("return '支持索引浏览、Mapping 检查、JSON DSL 和 query_string 查询';");
|
||||
expect(source).toContain(
|
||||
'type === "clickhouse" ? "default" : (type === "redis" || type === "elasticsearch") ? "" : "root";',
|
||||
);
|
||||
|
||||
@@ -63,6 +63,12 @@ import { resolveConnectionSecretDraft } from "../utils/connectionSecretDraft";
|
||||
import { getCustomConnectionDsnValidationMessage } from "../utils/customConnectionDsn";
|
||||
import { mergeParsedUriValuesForForm } from "../utils/connectionUriMerge";
|
||||
import { buildRpcConnectionConfig } from "../utils/connectionRpcConfig";
|
||||
import {
|
||||
CONNECTION_TYPE_GROUPS,
|
||||
getAllConnectionTypeCatalogItems,
|
||||
getConnectionTypeDefaultPort as getDefaultPortByType,
|
||||
getConnectionTypeHint,
|
||||
} from "../utils/connectionTypeCatalog";
|
||||
import { CUSTOM_CONNECTION_DRIVER_HELP } from "../utils/driverImportGuidance";
|
||||
import {
|
||||
describeUnsupportedOceanBaseProtocol,
|
||||
@@ -230,58 +236,6 @@ const resolveInitialSecretFieldValue = (
|
||||
}
|
||||
};
|
||||
|
||||
const getDefaultPortByType = (type: string) => {
|
||||
switch (type) {
|
||||
case "jvm":
|
||||
return 9010;
|
||||
case "mysql":
|
||||
return 3306;
|
||||
case "oceanbase":
|
||||
return 2881;
|
||||
case "doris":
|
||||
case "diros":
|
||||
case "starrocks":
|
||||
return 9030;
|
||||
case "sphinx":
|
||||
return 9306;
|
||||
case "clickhouse":
|
||||
return 9000;
|
||||
case "postgres":
|
||||
case "opengauss":
|
||||
return 5432;
|
||||
case "redis":
|
||||
return 6379;
|
||||
case "tdengine":
|
||||
return 6041;
|
||||
case "oracle":
|
||||
return 1521;
|
||||
case "dameng":
|
||||
return 5236;
|
||||
case "kingbase":
|
||||
return 54321;
|
||||
case "sqlserver":
|
||||
return 1433;
|
||||
case "iris":
|
||||
return 1972;
|
||||
case "mongodb":
|
||||
return 27017;
|
||||
case "elasticsearch":
|
||||
return 9200;
|
||||
case "highgo":
|
||||
return 5866;
|
||||
case "mariadb":
|
||||
return 3306;
|
||||
case "vastbase":
|
||||
return 5432;
|
||||
case "sqlite":
|
||||
return 0;
|
||||
case "duckdb":
|
||||
return 0;
|
||||
default:
|
||||
return 3306;
|
||||
}
|
||||
};
|
||||
|
||||
const singleHostUriSchemesByType: Record<string, string[]> = {
|
||||
postgres: ["postgresql", "postgres"],
|
||||
opengauss: ["opengauss", "jdbc:opengauss", "postgresql", "postgres"],
|
||||
@@ -4018,176 +3972,19 @@ const ConnectionModal: React.FC<{
|
||||
const driverStatusChecking =
|
||||
hasCurrentDriverType && !driverStatusLoaded && step === 2;
|
||||
|
||||
const dbTypeGroups = [
|
||||
{
|
||||
label: "关系型数据库",
|
||||
items: [
|
||||
{
|
||||
key: "mysql",
|
||||
name: "MySQL",
|
||||
icon: getDbIcon("mysql", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "mariadb",
|
||||
name: "MariaDB",
|
||||
icon: getDbIcon("mariadb", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "diros",
|
||||
name: "Doris",
|
||||
icon: getDbIcon("diros", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "starrocks",
|
||||
name: "StarRocks",
|
||||
icon: getDbIcon("starrocks", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "sphinx",
|
||||
name: "Sphinx",
|
||||
icon: getDbIcon("sphinx", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "clickhouse",
|
||||
name: "ClickHouse",
|
||||
icon: getDbIcon("clickhouse", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "postgres",
|
||||
name: "PostgreSQL",
|
||||
icon: getDbIcon("postgres", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "sqlserver",
|
||||
name: "SQL Server",
|
||||
icon: getDbIcon("sqlserver", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "iris",
|
||||
name: "InterSystems IRIS",
|
||||
icon: getDbIcon("iris", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "sqlite",
|
||||
name: "SQLite",
|
||||
icon: getDbIcon("sqlite", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "duckdb",
|
||||
name: "DuckDB",
|
||||
icon: getDbIcon("duckdb", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "oracle",
|
||||
name: "Oracle",
|
||||
icon: getDbIcon("oracle", undefined, 36),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "国产数据库",
|
||||
items: [
|
||||
{
|
||||
key: "oceanbase",
|
||||
name: "OceanBase",
|
||||
icon: getDbIcon("oceanbase", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "dameng",
|
||||
name: "Dameng (达梦)",
|
||||
icon: getDbIcon("dameng", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "kingbase",
|
||||
name: "Kingbase (人大金仓)",
|
||||
icon: getDbIcon("kingbase", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "highgo",
|
||||
name: "HighGo (瀚高)",
|
||||
icon: getDbIcon("highgo", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "vastbase",
|
||||
name: "Vastbase (海量)",
|
||||
icon: getDbIcon("vastbase", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "opengauss",
|
||||
name: "OpenGauss",
|
||||
icon: getDbIcon("opengauss", undefined, 36),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "NoSQL",
|
||||
items: [
|
||||
{
|
||||
key: "mongodb",
|
||||
name: "MongoDB",
|
||||
icon: getDbIcon("mongodb", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "redis",
|
||||
name: "Redis",
|
||||
icon: getDbIcon("redis", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "elasticsearch",
|
||||
name: "Elasticsearch",
|
||||
icon: getDbIcon("elasticsearch", undefined, 36),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "时序数据库",
|
||||
items: [
|
||||
{
|
||||
key: "tdengine",
|
||||
name: "TDengine",
|
||||
icon: getDbIcon("tdengine", undefined, 36),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "其他",
|
||||
items: [
|
||||
{
|
||||
key: "jvm",
|
||||
name: "JVM Runtime",
|
||||
icon: getDbIcon("jvm", undefined, 36),
|
||||
},
|
||||
{
|
||||
key: "custom",
|
||||
name: "Custom (自定义)",
|
||||
icon: getDbIcon("custom", undefined, 36),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
const dbTypeGroups = useMemo(
|
||||
() =>
|
||||
CONNECTION_TYPE_GROUPS.map((group) => ({
|
||||
...group,
|
||||
items: group.items.map((item) => ({
|
||||
...item,
|
||||
icon: getDbIcon(item.key, undefined, 36),
|
||||
})),
|
||||
})),
|
||||
[],
|
||||
);
|
||||
|
||||
const dbTypes = dbTypeGroups.flatMap((g) => g.items);
|
||||
const getDbTypeHint = (type: string) => {
|
||||
switch (type) {
|
||||
case "jvm":
|
||||
return "JMX / Endpoint / Agent";
|
||||
case "custom":
|
||||
return "自定义驱动与 DSN";
|
||||
case "redis":
|
||||
return "单机 / 集群";
|
||||
case "mongodb":
|
||||
return "单机 / 副本集";
|
||||
case "elasticsearch":
|
||||
return "支持索引浏览、Mapping 检查、JSON DSL 和 query_string 查询";
|
||||
case "oceanbase":
|
||||
return "MySQL / Oracle 租户";
|
||||
case "sqlite":
|
||||
case "duckdb":
|
||||
return "本地文件连接";
|
||||
default:
|
||||
return "标准连接配置";
|
||||
}
|
||||
};
|
||||
const dbTypes = getAllConnectionTypeCatalogItems();
|
||||
|
||||
const renderStep1 = () => (
|
||||
<div
|
||||
@@ -4344,7 +4141,7 @@ const ConnectionModal: React.FC<{
|
||||
{item.name}
|
||||
</Text>
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>
|
||||
{getDbTypeHint(item.key)}
|
||||
{getConnectionTypeHint(item.key)}
|
||||
</Text>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
53
frontend/src/utils/connectionTypeCatalog.test.ts
Normal file
53
frontend/src/utils/connectionTypeCatalog.test.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
CONNECTION_TYPE_GROUPS,
|
||||
getAllConnectionTypeCatalogItems,
|
||||
getConnectionTypeDefaultPort,
|
||||
getConnectionTypeHint,
|
||||
} from './connectionTypeCatalog';
|
||||
|
||||
describe('connectionTypeCatalog', () => {
|
||||
it('keeps supported connection types grouped for the creation modal', () => {
|
||||
expect(CONNECTION_TYPE_GROUPS.map((group) => group.label)).toEqual([
|
||||
'关系型数据库',
|
||||
'国产数据库',
|
||||
'NoSQL',
|
||||
'时序数据库',
|
||||
'其他',
|
||||
]);
|
||||
|
||||
const keys = getAllConnectionTypeCatalogItems().map((item) => item.key);
|
||||
expect(keys).toContain('mysql');
|
||||
expect(keys).toContain('oceanbase');
|
||||
expect(keys).toContain('mongodb');
|
||||
expect(keys).toContain('redis');
|
||||
expect(keys).toContain('elasticsearch');
|
||||
expect(keys).toContain('jvm');
|
||||
expect(keys).toContain('custom');
|
||||
expect(new Set(keys).size).toBe(keys.length);
|
||||
});
|
||||
|
||||
it('returns the existing default port mapping for supported connection types', () => {
|
||||
expect(getConnectionTypeDefaultPort('mysql')).toBe(3306);
|
||||
expect(getConnectionTypeDefaultPort('oceanbase')).toBe(2881);
|
||||
expect(getConnectionTypeDefaultPort('diros')).toBe(9030);
|
||||
expect(getConnectionTypeDefaultPort('postgres')).toBe(5432);
|
||||
expect(getConnectionTypeDefaultPort('redis')).toBe(6379);
|
||||
expect(getConnectionTypeDefaultPort('oracle')).toBe(1521);
|
||||
expect(getConnectionTypeDefaultPort('mongodb')).toBe(27017);
|
||||
expect(getConnectionTypeDefaultPort('elasticsearch')).toBe(9200);
|
||||
expect(getConnectionTypeDefaultPort('sqlite')).toBe(0);
|
||||
expect(getConnectionTypeDefaultPort('duckdb')).toBe(0);
|
||||
expect(getConnectionTypeDefaultPort('unknown')).toBe(3306);
|
||||
});
|
||||
|
||||
it('keeps concise localized hints for special connection types', () => {
|
||||
expect(getConnectionTypeHint('redis')).toBe('单机 / 集群');
|
||||
expect(getConnectionTypeHint('mongodb')).toBe('单机 / 副本集');
|
||||
expect(getConnectionTypeHint('elasticsearch')).toContain('Mapping');
|
||||
expect(getConnectionTypeHint('oceanbase')).toBe('MySQL / Oracle 租户');
|
||||
expect(getConnectionTypeHint('duckdb')).toBe('本地文件连接');
|
||||
expect(getConnectionTypeHint('mysql')).toBe('标准连接配置');
|
||||
});
|
||||
});
|
||||
137
frontend/src/utils/connectionTypeCatalog.ts
Normal file
137
frontend/src/utils/connectionTypeCatalog.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
export type ConnectionTypeCatalogItem = {
|
||||
key: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type ConnectionTypeCatalogGroup = {
|
||||
label: string;
|
||||
items: ConnectionTypeCatalogItem[];
|
||||
};
|
||||
|
||||
export const CONNECTION_TYPE_GROUPS: ConnectionTypeCatalogGroup[] = [
|
||||
{
|
||||
label: '关系型数据库',
|
||||
items: [
|
||||
{ key: 'mysql', name: 'MySQL' },
|
||||
{ key: 'mariadb', name: 'MariaDB' },
|
||||
{ key: 'diros', name: 'Doris' },
|
||||
{ key: 'starrocks', name: 'StarRocks' },
|
||||
{ key: 'sphinx', name: 'Sphinx' },
|
||||
{ key: 'clickhouse', name: 'ClickHouse' },
|
||||
{ key: 'postgres', name: 'PostgreSQL' },
|
||||
{ key: 'sqlserver', name: 'SQL Server' },
|
||||
{ key: 'iris', name: 'InterSystems IRIS' },
|
||||
{ key: 'sqlite', name: 'SQLite' },
|
||||
{ key: 'duckdb', name: 'DuckDB' },
|
||||
{ key: 'oracle', name: 'Oracle' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '国产数据库',
|
||||
items: [
|
||||
{ key: 'oceanbase', name: 'OceanBase' },
|
||||
{ key: 'dameng', name: 'Dameng (达梦)' },
|
||||
{ key: 'kingbase', name: 'Kingbase (人大金仓)' },
|
||||
{ key: 'highgo', name: 'HighGo (瀚高)' },
|
||||
{ key: 'vastbase', name: 'Vastbase (海量)' },
|
||||
{ key: 'opengauss', name: 'OpenGauss' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'NoSQL',
|
||||
items: [
|
||||
{ key: 'mongodb', name: 'MongoDB' },
|
||||
{ key: 'redis', name: 'Redis' },
|
||||
{ key: 'elasticsearch', name: 'Elasticsearch' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '时序数据库',
|
||||
items: [
|
||||
{ key: 'tdengine', name: 'TDengine' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '其他',
|
||||
items: [
|
||||
{ key: 'jvm', name: 'JVM Runtime' },
|
||||
{ key: 'custom', name: 'Custom (自定义)' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const getConnectionTypeDefaultPort = (type: string): number => {
|
||||
switch (String(type || '').trim().toLowerCase()) {
|
||||
case 'jvm':
|
||||
return 9010;
|
||||
case 'mysql':
|
||||
return 3306;
|
||||
case 'oceanbase':
|
||||
return 2881;
|
||||
case 'doris':
|
||||
case 'diros':
|
||||
case 'starrocks':
|
||||
return 9030;
|
||||
case 'sphinx':
|
||||
return 9306;
|
||||
case 'clickhouse':
|
||||
return 9000;
|
||||
case 'postgres':
|
||||
case 'opengauss':
|
||||
return 5432;
|
||||
case 'redis':
|
||||
return 6379;
|
||||
case 'tdengine':
|
||||
return 6041;
|
||||
case 'oracle':
|
||||
return 1521;
|
||||
case 'dameng':
|
||||
return 5236;
|
||||
case 'kingbase':
|
||||
return 54321;
|
||||
case 'sqlserver':
|
||||
return 1433;
|
||||
case 'iris':
|
||||
return 1972;
|
||||
case 'mongodb':
|
||||
return 27017;
|
||||
case 'elasticsearch':
|
||||
return 9200;
|
||||
case 'highgo':
|
||||
return 5866;
|
||||
case 'mariadb':
|
||||
return 3306;
|
||||
case 'vastbase':
|
||||
return 5432;
|
||||
case 'sqlite':
|
||||
case 'duckdb':
|
||||
return 0;
|
||||
default:
|
||||
return 3306;
|
||||
}
|
||||
};
|
||||
|
||||
export const getConnectionTypeHint = (type: string): string => {
|
||||
switch (String(type || '').trim().toLowerCase()) {
|
||||
case 'jvm':
|
||||
return 'JMX / Endpoint / Agent';
|
||||
case 'custom':
|
||||
return '自定义驱动与 DSN';
|
||||
case 'redis':
|
||||
return '单机 / 集群';
|
||||
case 'mongodb':
|
||||
return '单机 / 副本集';
|
||||
case 'elasticsearch':
|
||||
return '支持索引浏览、Mapping 检查、JSON DSL 和 query_string 查询';
|
||||
case 'oceanbase':
|
||||
return 'MySQL / Oracle 租户';
|
||||
case 'sqlite':
|
||||
case 'duckdb':
|
||||
return '本地文件连接';
|
||||
default:
|
||||
return '标准连接配置';
|
||||
}
|
||||
};
|
||||
|
||||
export const getAllConnectionTypeCatalogItems = (): ConnectionTypeCatalogItem[] =>
|
||||
CONNECTION_TYPE_GROUPS.flatMap((group) => group.items);
|
||||
Reference in New Issue
Block a user