Files
MyGoNavi/frontend/src/utils/connectionModalPresentation.ts
Syngnat cef273f228 feat(nacos): 新增 Nacos 数据源管理能力
- 支持 Nacos 连接测试及多命名空间资源树
- 提供配置搜索、发布、删除、历史回滚和变更监听
- 增加 Beta 发布、配置导入导出与批量操作
- 支持服务发现、实例管理、只读保护和多语言界面
- 补充 Wails 接口绑定及前后端回归测试

Refs #756
2026-07-28 15:58:22 +08:00

440 lines
9.1 KiB
TypeScript

import { t } from '../i18n';
type StoredSecretPlaceholderOptions = {
hasStoredSecret?: boolean;
emptyPlaceholder: string;
retainedLabel: string;
};
type ConnectionTestFailureKind =
| 'validation'
| 'runtime'
| 'driver_unavailable'
| 'secret_blocked';
type ConnectionTestFailureFeedback = {
message: string;
shouldToast: boolean;
};
export type ConnectionConfigSectionKey =
| 'identity'
| 'uri'
| 'target'
| 'fileTarget'
| 'readOnly'
| 'connectionMode'
| 'oceanBaseProtocol'
| 'mongoDiscovery'
| 'replica'
| 'service'
| 'mongoPolicy'
| 'credentials'
| 'databaseScope'
| 'customDriver'
| 'customDsn'
| 'jvmRuntime';
export type ConnectionConfigLayoutKind =
| 'mysql-compatible'
| 'mongodb'
| 'redis'
| 'postgres-compatible'
| 'oracle'
| 'file'
| 'search'
| 'vector'
| 'timeseries'
| 'custom'
| 'jvm'
| 'nacos'
| 'generic-sql';
export type ConnectionConfigLayout = {
kind: ConnectionConfigLayoutKind;
sections: ConnectionConfigSectionKey[];
};
type ConnectionConfigSectionCopy = {
title: string;
description: string;
};
const mysqlCompatibleTypes = new Set([
'mysql',
'goldendb',
'mariadb',
'oceanbase',
'doris',
'diros',
'starrocks',
'sphinx',
]);
const postgresCompatibleTypes = new Set([
'postgres',
'kingbase',
'highgo',
'vastbase',
'opengauss',
'gaussdb',
]);
const fileDatabaseTypes = new Set(['sqlite', 'duckdb']);
const connectionConfigSectionKeyMap: Record<
ConnectionConfigSectionKey,
string
> = {
identity: 'identity',
uri: 'uri',
target: 'target',
fileTarget: 'fileTarget',
readOnly: 'readOnly',
connectionMode: 'connectionMode',
oceanBaseProtocol: 'oceanBaseProtocol',
mongoDiscovery: 'mongoDiscovery',
replica: 'replica',
service: 'service',
mongoPolicy: 'mongoPolicy',
credentials: 'credentials',
databaseScope: 'databaseScope',
customDriver: 'customDriver',
customDsn: 'customDsn',
jvmRuntime: 'jvmRuntime',
};
export const getConnectionConfigSectionCopy = (
key: ConnectionConfigSectionKey,
): ConnectionConfigSectionCopy => ({
title: t(`connection.modal.section.${connectionConfigSectionKeyMap[key]}.title`),
description: t(
`connection.modal.section.${connectionConfigSectionKeyMap[key]}.description`,
),
});
export const getConnectionConfigLayoutKindLabel = (
kind: ConnectionConfigLayoutKind,
): string => {
switch (kind) {
case 'mysql-compatible':
return t('connection.modal.layoutKind.mysqlCompatible');
case 'mongodb':
return t('connection.modal.layoutKind.mongodb');
case 'redis':
return t('connection.modal.layoutKind.redis');
case 'postgres-compatible':
return t('connection.modal.layoutKind.postgresCompatible');
case 'oracle':
return t('connection.modal.layoutKind.oracle');
case 'file':
return t('connection.modal.layoutKind.file');
case 'search':
return t('connection.modal.layoutKind.search');
case 'vector':
return t('connection.modal.layoutKind.vector');
case 'timeseries':
return t('connection.modal.layoutKind.timeseries');
case 'custom':
return t('connection.modal.layoutKind.custom');
case 'jvm':
return t('connection.modal.layoutKind.jvm');
case 'nacos':
return t('connection.modal.layoutKind.nacos');
case 'generic-sql':
default:
return t('connection.modal.layoutKind.genericSql');
}
};
export const resolveConnectionConfigLayout = (
rawType: string,
): ConnectionConfigLayout => {
const type = String(rawType || '').trim().toLowerCase();
if (type === 'jvm') {
return {
kind: 'jvm',
sections: ['identity', 'jvmRuntime'],
};
}
if (type === 'custom') {
return {
kind: 'custom',
sections: ['identity', 'customDriver', 'customDsn'],
};
}
if (fileDatabaseTypes.has(type)) {
return {
kind: 'file',
sections: ['identity', 'uri', 'fileTarget'],
};
}
if (mysqlCompatibleTypes.has(type)) {
return {
kind: 'mysql-compatible',
sections: [
'identity',
'uri',
'target',
'connectionMode',
'replica',
'credentials',
'databaseScope',
],
};
}
if (type === 'mongodb') {
return {
kind: 'mongodb',
sections: [
'identity',
'uri',
'target',
'connectionMode',
'mongoDiscovery',
'replica',
'mongoPolicy',
'credentials',
'databaseScope',
],
};
}
if (type === 'redis') {
return {
kind: 'redis',
sections: [
'identity',
'uri',
'target',
'connectionMode',
'credentials',
'databaseScope',
],
};
}
if (type === 'nacos') {
return {
kind: 'nacos',
sections: [
'identity',
'uri',
'target',
'credentials',
],
};
}
if (type === 'elasticsearch') {
return {
kind: 'search',
sections: [
'identity',
'uri',
'target',
'service',
'credentials',
'databaseScope',
],
};
}
if (type === 'chroma' || type === 'qdrant' || type === 'milvus') {
return {
kind: 'vector',
sections: [
'identity',
'uri',
'target',
'service',
'credentials',
'databaseScope',
],
};
}
if (type === 'iotdb') {
return {
kind: 'timeseries',
sections: [
'identity',
'uri',
'target',
'service',
'credentials',
'databaseScope',
],
};
}
if (type === 'mqtt') {
return {
kind: 'generic-sql',
sections: [
'identity',
'uri',
'target',
'connectionMode',
'replica',
'service',
'credentials',
],
};
}
if (type === 'rocketmq') {
return {
kind: 'generic-sql',
sections: [
'identity',
'uri',
'target',
'connectionMode',
'replica',
'service',
'credentials',
],
};
}
if (type === 'kafka') {
return {
kind: 'generic-sql',
sections: [
'identity',
'uri',
'target',
'connectionMode',
'replica',
'service',
'credentials',
],
};
}
if (type === 'rabbitmq') {
return {
kind: 'generic-sql',
sections: [
'identity',
'uri',
'target',
'service',
'credentials',
'databaseScope',
],
};
}
if (type === 'trino') {
return {
kind: 'generic-sql',
sections: [
'identity',
'uri',
'target',
'service',
'credentials',
'databaseScope',
],
};
}
if (postgresCompatibleTypes.has(type)) {
return {
kind: 'postgres-compatible',
sections: [
'identity',
'uri',
'target',
'service',
'credentials',
'databaseScope',
],
};
}
if (type === 'oracle') {
return {
kind: 'oracle',
sections: [
'identity',
'uri',
'target',
'service',
'credentials',
'databaseScope',
],
};
}
return {
kind: 'generic-sql',
sections: ['identity', 'uri', 'target', 'credentials', 'databaseScope'],
};
};
const normalizeText = (value: unknown, fallback = ''): string => {
const text = String(value ?? '').trim();
if (!text || text === 'undefined' || text === 'null') {
return fallback;
}
return text;
};
export const getStoredSecretPlaceholder = ({
hasStoredSecret,
emptyPlaceholder,
retainedLabel,
}: StoredSecretPlaceholderOptions): string => (
hasStoredSecret
? t('connection.modal.secret.placeholder.retained', { retainedLabel })
: emptyPlaceholder
);
export const normalizeConnectionSecretErrorMessage = (
value: unknown,
fallback = '',
): string => {
const text = normalizeText(value, fallback);
const lower = text.toLowerCase();
if (lower.includes('saved connection not found:')) {
return t('connection.modal.error.savedConnectionNotFound');
}
if (lower.includes('secret store unavailable')) {
return t('connection.modal.error.secretStoreUnavailable');
}
return text;
};
export const summarizeConnectionTestFailureMessage = (
value: unknown,
fallback = '',
): string => {
const text = normalizeConnectionSecretErrorMessage(value, fallback);
const [firstLine] = text
.split(/\r?\n/)
.map((item) => item.trim())
.filter((item) => item !== '');
return firstLine || text;
};
export const resolveConnectionTestFailureFeedback = ({
kind,
reason,
fallback,
}: {
kind: ConnectionTestFailureKind;
reason: unknown;
fallback: string;
}): ConnectionTestFailureFeedback => {
if (kind === 'validation') {
return {
message: t('connection.modal.test.validation'),
shouldToast: false,
};
}
return {
message: t('connection.modal.test.failure', {
reason: normalizeConnectionSecretErrorMessage(reason, fallback),
}),
shouldToast: false,
};
};
export type {
ConnectionTestFailureFeedback,
ConnectionTestFailureKind,
};