✨ feat(connection): 新增数据库连接图标功能并修复达梦数据库列表为空
- 图标组件:新增 DatabaseIcons.tsx,10 种品牌 SVG logo + 7 种彩色文字标签覆盖全部数据源 - 品牌资源:下载 MySQL/PG/Redis/MongoDB/ClickHouse/SQLite/MariaDB/Doris/Sphinx/DuckDB 的 SVG(CC0 许可) - 类型扩展:SavedConnection 新增 iconType/iconColor 支持自定义图标和颜色 - 外观配置:ConnectionModal 新增"外观"配置区(图标选择器 + 14 色选择器 + 预览面板) - 数据源选择:Step1 数据源类型卡片全部统一为品牌图标 - 达梦修复:dameng_metadata.go 增加原生 SQL 查询和诊断日志,改善数据库列表获取 - refs #114 - refs #266
1
frontend/public/db-icons/clickhouse.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>ClickHouse</title><path d="M21.333 10H24v4h-2.667ZM16 1.335h2.667v21.33H16Zm-5.333 0h2.666v21.33h-2.666ZM0 22.665V1.335h2.667v21.33zm5.333-21.33H8v21.33H5.333Z"/></svg>
|
||||
|
After Width: | Height: | Size: 246 B |
1
frontend/public/db-icons/diros.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Apache Doris</title><path d="M8.666.0001c-.5355-.004-1.068.1072-1.5241.3384-.207.1048-.5749.3802-.8177.6118-1.0278.9803-1.2876 2.5138-.6553 3.8679.205.439.5068.7694 2.8476 3.1166 2.4527 2.4594 2.6352 2.6255 2.8852 2.6258.2446.0003.3647-.099 1.4408-1.19.9367-.9496 1.2306-1.2992 1.4536-1.7286.5966-1.149.6487-2.0513.174-3.014-.2264-.459-.4816-.7514-1.9012-2.176-.9018-.9052-1.7907-1.7496-1.9751-1.8765C10.0488.2005 9.3548.0052 8.666 0ZM3.5518 5.5737c-.2176.0031-.6097.085-.6097.3285v12.0904l.1642.175c.1123.1194.2498.1748.4342.1748.2545 0 .4436-.1738 3.349-3.0786 2.6868-2.6862 3.079-2.909 3.0791-3.305.0002-.3961-.3924-.6194-3.0784-3.306-2.8612-2.8619-3.0968-3.079-3.3384-3.079Zm13.0967.861c-.0481.0184-.112.1636-.1418.3225-.0756.403-.3719 1.109-.6572 1.5663-.1407.2253-2.2392 2.3955-5.049 5.2212-2.7513 2.7667-4.9104 4.9985-5.0468 5.2165-.4552.7275-.5967 1.3905-.4684 2.1964.222 1.3947 1.3263 2.6812 2.5486 2.9693.4667.11 1.618.0927 2.0329-.0305.2084-.062.526-.2112.7055-.3318.5023-.3373 9.341-9.0562 9.6463-9.5154.449-.6753.8356-1.0716.8395-1.9762-.0056-.5935-.1305-1.1138-1.0715-2.306-.5094-.6523-3.2341-3.3723-3.338-3.3324Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
1
frontend/public/db-icons/duckdb.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>DuckDB</title><path d="M12 0C5.363 0 0 5.363 0 12s5.363 12 12 12 12-5.363 12-12S18.637 0 12 0zM9.502 7.03a4.974 4.974 0 0 1 4.97 4.97 4.974 4.974 0 0 1-4.97 4.97A4.974 4.974 0 0 1 4.532 12a4.974 4.974 0 0 1 4.97-4.97zm6.563 3.183h2.351c.98 0 1.787.782 1.787 1.762s-.807 1.789-1.787 1.789h-2.351v-3.551z"/></svg>
|
||||
|
After Width: | Height: | Size: 389 B |
1
frontend/public/db-icons/mariadb.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>MariaDB</title><path d="M23.157 4.412c-.676.284-.79.31-1.673.372-.65.045-.757.057-1.212.209-.75.246-1.395.75-2.02 1.59-.296.398-1.249 1.913-1.249 1.988 0 .057-.65.998-.915 1.32-.574.713-1.08 1.079-2.14 1.59-.77.36-1.224.524-4.102 1.477-1.073.353-2.133.738-2.367.864-.852.449-1.515 1.036-2.203 1.938-1.003 1.32-.972 1.313-3.042.947a12.264 12.264 0 00-.675-.063c-.644-.05-1.023.044-1.332.334L0 17.193l.177.088c.094.05.353.234.561.398.215.17.461.347.55.391.088.044.17.088.183.101.012.013-.089.17-.228.353-.435.581-.593.871-.574 1.048.019.164.032.17.43.17.517-.006.826-.056 1.261-.208.65-.233 2.058-.94 2.784-1.4.776-.5 1.717-.998 1.956-1.042.082-.02.354-.07.594-.114.58-.107 1.464-.095 2.587.05.108.013.373.045.6.064.227.025.43.057.454.076.026.012.474.037.998.056.934.026 1.104.007 1.3-.189.126-.133.385-.631.498-.985.209-.643.417-.921.366-.492-.113.966-.322 1.692-.713 2.411-.259.499-.663 1.092-.934 1.395-.322.347-.315.36.088.315.619-.063 1.471-.397 2.096-.82.827-.562 1.647-1.691 2.19-3.03.107-.27.22-.22.183.083-.013.094-.038.315-.057.498l-.031.328.353-.202c.833-.48 1.414-1.262 2.127-2.884.227-.518.877-2.922 1.073-3.976a9.64 9.64 0 01.271-1.042c.127-.429.196-.555.48-.858.183-.19.625-.555.978-.808.72-.505.953-.75 1.187-1.205.208-.417.284-1.13.132-1.357-.132-.202-.284-.196-.763.006Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
frontend/public/db-icons/mongodb.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>MongoDB</title><path d="M17.193 9.555c-1.264-5.58-4.252-7.414-4.573-8.115-.28-.394-.53-.954-.735-1.44-.036.495-.055.685-.523 1.184-.723.566-4.438 3.682-4.74 10.02-.282 5.912 4.27 9.435 4.888 9.884l.07.05A73.49 73.49 0 0111.91 24h.481c.114-1.032.284-2.056.51-3.07.417-.296.604-.463.85-.693a11.342 11.342 0 003.639-8.464c.01-.814-.103-1.662-.197-2.218zm-5.336 8.195s0-8.291.275-8.29c.213 0 .49 10.695.49 10.695-.381-.045-.765-1.76-.765-2.405z"/></svg>
|
||||
|
After Width: | Height: | Size: 527 B |
1
frontend/public/db-icons/mysql.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>MySQL</title><path d="M16.405 5.501c-.115 0-.193.014-.274.033v.013h.014c.054.104.146.18.214.273.054.107.1.214.154.32l.014-.015c.094-.066.14-.172.14-.333-.04-.047-.046-.094-.08-.14-.04-.067-.126-.1-.18-.153zM5.77 18.695h-.927a50.854 50.854 0 00-.27-4.41h-.008l-1.41 4.41H2.45l-1.4-4.41h-.01a72.892 72.892 0 00-.195 4.41H0c.055-1.966.192-3.81.41-5.53h1.15l1.335 4.064h.008l1.347-4.064h1.095c.242 2.015.384 3.86.428 5.53zm4.017-4.08c-.378 2.045-.876 3.533-1.492 4.46-.482.716-1.01 1.073-1.583 1.073-.153 0-.34-.046-.566-.138v-.494c.11.017.24.026.386.026.268 0 .483-.075.647-.222.197-.18.295-.382.295-.605 0-.155-.077-.47-.23-.944L6.23 14.615h.91l.727 2.36c.164.536.233.91.205 1.123.4-1.064.678-2.227.835-3.483zm12.325 4.08h-2.63v-5.53h.885v4.85h1.745zm-3.32.135l-1.016-.5c.09-.076.177-.158.255-.25.433-.506.648-1.258.648-2.253 0-1.83-.718-2.746-2.155-2.746-.704 0-1.254.232-1.65.697-.43.508-.646 1.256-.646 2.245 0 .972.19 1.686.574 2.14.35.41.877.615 1.583.615.264 0 .506-.033.725-.098l1.325.772.36-.622zM15.5 17.588c-.225-.36-.337-.94-.337-1.736 0-1.393.424-2.09 1.27-2.09.443 0 .77.167.977.5.224.362.336.936.336 1.723 0 1.404-.424 2.108-1.27 2.108-.445 0-.77-.167-.978-.5zm-1.658-.425c0 .47-.172.856-.516 1.156-.344.3-.803.45-1.384.45-.543 0-1.064-.172-1.573-.515l.237-.476c.438.22.833.328 1.19.328.332 0 .593-.073.783-.22a.754.754 0 00.3-.615c0-.33-.23-.61-.648-.845-.388-.213-1.163-.657-1.163-.657-.422-.307-.632-.636-.632-1.177 0-.45.157-.81.47-1.085.315-.278.72-.415 1.22-.415.512 0 .98.136 1.4.41l-.213.476a2.726 2.726 0 00-1.064-.23c-.283 0-.502.068-.654.206a.685.685 0 00-.248.524c0 .328.234.61.666.85.393.215 1.187.67 1.187.67.433.305.648.63.648 1.168zm9.382-5.852c-.535-.014-.95.04-1.297.188-.1.04-.26.04-.274.167.055.053.063.14.11.214.08.134.218.313.346.407.14.11.28.216.427.31.26.16.555.255.81.416.145.094.293.213.44.313.073.05.12.14.214.172v-.02c-.046-.06-.06-.147-.105-.214-.067-.067-.134-.127-.2-.193a3.223 3.223 0 00-.695-.675c-.214-.146-.682-.35-.77-.595l-.013-.014c.146-.013.32-.066.46-.106.227-.06.435-.047.67-.106.106-.027.213-.06.32-.094v-.06c-.12-.12-.21-.283-.334-.395a8.867 8.867 0 00-1.104-.823c-.21-.134-.476-.22-.697-.334-.08-.04-.214-.06-.26-.127-.12-.146-.19-.34-.275-.514a17.69 17.69 0 01-.547-1.163c-.12-.262-.193-.523-.34-.763-.69-1.137-1.437-1.826-2.586-2.5-.247-.14-.543-.2-.856-.274-.167-.008-.334-.02-.5-.027-.11-.047-.216-.174-.31-.235-.38-.24-1.364-.76-1.644-.072-.18.434.267.862.422 1.082.115.153.26.328.34.5.047.116.06.235.107.356.106.294.207.622.347.897.073.14.153.287.247.413.054.073.146.107.167.227-.094.136-.1.334-.154.5-.24.757-.146 1.693.194 2.25.107.166.362.534.703.393.3-.12.234-.5.32-.835.02-.08.007-.133.048-.187v.015c.094.188.188.367.274.555.206.328.566.668.867.895.16.12.287.328.487.402v-.02h-.015c-.043-.058-.1-.086-.154-.133a3.445 3.445 0 01-.35-.4 8.76 8.76 0 01-.747-1.218c-.11-.21-.202-.436-.29-.643-.04-.08-.04-.2-.107-.24-.1.146-.247.273-.32.453-.127.288-.14.642-.188 1.01-.027.007-.014 0-.027.014-.214-.052-.287-.274-.367-.46-.2-.475-.233-1.238-.06-1.785.047-.14.247-.582.167-.716-.042-.127-.174-.2-.247-.303a2.478 2.478 0 01-.24-.427c-.16-.374-.24-.788-.414-1.162-.08-.173-.22-.354-.334-.513-.127-.18-.267-.307-.368-.52-.033-.073-.08-.194-.027-.274.014-.054.042-.075.094-.09.088-.072.335.022.422.062.247.1.455.194.662.334.094.066.195.193.315.226h.14c.214.047.455.014.655.073.355.114.675.28.962.46a5.953 5.953 0 012.085 2.286c.08.154.115.295.188.455.14.33.313.663.455.982.14.315.275.636.476.897.1.14.502.213.682.286.133.06.34.115.46.188.23.14.454.3.67.454.11.076.443.243.463.378z"/></svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
1
frontend/public/db-icons/postgres.svg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
1
frontend/public/db-icons/redis.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Redis</title><path d="M22.71 13.145c-1.66 2.092-3.452 4.483-7.038 4.483-3.203 0-4.397-2.825-4.48-5.12.701 1.484 2.073 2.685 4.214 2.63 4.117-.133 6.94-3.852 6.94-7.239 0-4.05-3.022-6.972-8.268-6.972-3.752 0-8.4 1.428-11.455 3.685C2.59 6.937 3.885 9.958 4.35 9.626c2.648-1.904 4.748-3.13 6.784-3.744C8.12 9.244.886 17.05 0 18.425c.1 1.261 1.66 4.648 2.424 4.648.232 0 .431-.133.664-.365a100.49 100.49 0 0 0 5.54-6.765c.222 3.104 1.748 6.898 6.014 6.898 3.819 0 7.604-2.756 9.33-8.965.2-.764-.73-1.361-1.261-.73zm-4.349-5.013c0 1.959-1.926 2.922-3.685 2.922-.941 0-1.664-.247-2.235-.568 1.051-1.592 2.092-3.225 3.21-4.973 1.972.334 2.71 1.43 2.71 2.619z"/></svg>
|
||||
|
After Width: | Height: | Size: 738 B |
1
frontend/public/db-icons/sphinx.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Sphinx</title><path d="M16.284 19.861c0-.654.177-1.834.393-2.623.499-1.822.774-4.079.497-4.079-.116 0-.959.762-1.873 1.694-3.472 3.54-7.197 5.543-10.312 5.543-1.778 0-2.987-.45-4.154-1.545C.128 18.186 0 17.858 0 16.703c0-1.188.117-1.468.909-2.175.718-.642 1.171-.813 2.157-.813.76.171 1.21.16 1.457.461.251.296.338 1.265.035 1.832-.162.303-.585.491-1.105.491-.49 0-.77-.116-.669-.278.315-.511-.135-.857-.713-.548-.699.374-.711 1.698-.021 2.322.969.878 3.65 1.208 5.262.648 1.743-.605 4.022-2.061 5.841-3.732l1.6-1.469-2.088-.013c-2.186-.012-3.608-.273-8.211-1.506-1.531-.41-3.003-.765-3.271-.789-.304-.026-.503-.274-.487-.656.027-.646.378-1.127.793-1.308.249-.109 1.977-.274 3.809-.761 7.136-1.898 7.569-1.629 12.323-.426 1.553.393 3.351.821 4.147.835 1.227.022 1.493.124 1.74.666.16.351.291.686.291.745 0 .058-.695.424-1.545.813-3.12 1.428-4.104 2.185-3.088 3.635.421.602.412.666-.14 1.052-.323.227-.59.687-.593 1.022-.009.908-.583 2.856-1.417 3.624l-.732.675v-1.189Zm1.594-8.328c1.242-.346 1.994-.738 3.539-1.562-1.272-.372-4.462-.895-4.462-.895-2.354-.472-2.108-.448-2.214.071a3.475 3.475 0 0 1-.45 1.105c-.541.848-2.521 1.026-3.656.483-.356-.171-.714-.821-.709-1.283.007-.65-.362-.801-.598-.714-.191.07-.813.079-2.179.448-4.514 1.217-5.132 1.078-2.189 1.495.353.05 2.223.572 3.136.815 2.239.597 2.658.641 5.556.581 2.015-.042 2.858-.163 4.226-.544ZM.732 6.258c.056-.577.088-.702 1.692-1.025.919-.185 3.185-.785 5.036-1.333 4.254-1.26 5.462-1.263 9.873-.026 1.904.535 4.037.973 4.74.975 1.097.002 1.668.487 1.668.487.505 1.16.412 1.24-1.558 1.24-1.374 0-2.558-.232-4.385-.857-1.389-.476-3.369-.923-4.451-1.004-1.974-.149-1.971-.15-8.072 1.529-1.072.295-2.553.624-3.29.732l-1.342.196.089-.914Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
1
frontend/public/db-icons/sqlite.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>SQLite</title><path d="M21.678.521c-1.032-.92-2.28-.55-3.513.544a8.71 8.71 0 0 0-.547.535c-2.109 2.237-4.066 6.38-4.674 9.544.237.48.422 1.093.544 1.561a13.044 13.044 0 0 1 .164.703s-.019-.071-.096-.296l-.05-.146a1.689 1.689 0 0 0-.033-.08c-.138-.32-.518-.995-.686-1.289-.143.423-.27.818-.376 1.176.484.884.778 2.4.778 2.4s-.025-.099-.147-.442c-.107-.303-.644-1.244-.772-1.464-.217.804-.304 1.346-.226 1.478.152.256.296.698.422 1.186.286 1.1.485 2.44.485 2.44l.017.224a22.41 22.41 0 0 0 .056 2.748c.095 1.146.273 2.13.5 2.657l.155-.084c-.334-1.038-.47-2.399-.41-3.967.09-2.398.642-5.29 1.661-8.304 1.723-4.55 4.113-8.201 6.3-9.945-1.993 1.8-4.692 7.63-5.5 9.788-.904 2.416-1.545 4.684-1.931 6.857.666-2.037 2.821-2.912 2.821-2.912s1.057-1.304 2.292-3.166c-.74.169-1.955.458-2.362.629-.6.251-.762.337-.762.337s1.945-1.184 3.613-1.72C21.695 7.9 24.195 2.767 21.678.521m-18.573.543A1.842 1.842 0 0 0 1.27 2.9v16.608a1.84 1.84 0 0 0 1.835 1.834h9.418a22.953 22.953 0 0 1-.052-2.707c-.006-.062-.011-.141-.016-.2a27.01 27.01 0 0 0-.473-2.378c-.121-.47-.275-.898-.369-1.057-.116-.197-.098-.31-.097-.432 0-.12.015-.245.037-.386a9.98 9.98 0 0 1 .234-1.045l.217-.028c-.017-.035-.014-.065-.031-.097l-.041-.381a32.8 32.8 0 0 1 .382-1.194l.2-.019c-.008-.016-.01-.038-.018-.053l-.043-.316c.63-3.28 2.587-7.443 4.8-9.791.066-.069.133-.128.198-.194Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect, useRef, useMemo } from 'react';
|
||||
import { Modal, Form, Input, InputNumber, Button, message, Checkbox, Divider, Select, Alert, Card, Row, Col, Typography, Collapse, Space, Table, Tag } from 'antd';
|
||||
import { DatabaseOutlined, ConsoleSqlOutlined, FileTextOutlined, CloudServerOutlined, AppstoreAddOutlined, CloudOutlined, CheckCircleFilled, CloseCircleFilled, LinkOutlined, EditOutlined, AppstoreOutlined } from '@ant-design/icons';
|
||||
import { DatabaseOutlined, ConsoleSqlOutlined, FileTextOutlined, CloudServerOutlined, AppstoreAddOutlined, CloudOutlined, CheckCircleFilled, CloseCircleFilled, LinkOutlined, EditOutlined, AppstoreOutlined, BgColorsOutlined } from '@ant-design/icons';
|
||||
import { getDbIcon, getDbDefaultColor, getDbIconLabel, DB_ICON_TYPES, PRESET_ICON_COLORS } from './DatabaseIcons';
|
||||
import { useStore } from '../store';
|
||||
import { buildOverlayWorkbenchTheme } from '../utils/overlayWorkbenchTheme';
|
||||
import { normalizeOpacityForPlatform, resolveAppearanceValues } from '../utils/appearance';
|
||||
@@ -105,7 +106,9 @@ const ConnectionModal: React.FC<{
|
||||
const [dbType, setDbType] = useState('mysql');
|
||||
const [step, setStep] = useState(1); // 1: Select Type, 2: Configure
|
||||
const [activeGroup, setActiveGroup] = useState(0); // Active category index in step 1
|
||||
const [activeConfigSection, setActiveConfigSection] = useState<'basic' | 'network'>('basic');
|
||||
const [activeConfigSection, setActiveConfigSection] = useState<'basic' | 'network' | 'appearance'>('basic');
|
||||
const [customIconType, setCustomIconType] = useState<string | undefined>(undefined);
|
||||
const [customIconColor, setCustomIconColor] = useState<string | undefined>(undefined);
|
||||
const [activeNetworkConfig, setActiveNetworkConfig] = useState<'ssl' | 'ssh' | 'proxy' | 'httpTunnel'>('ssl');
|
||||
const [testResult, setTestResult] = useState<{ type: 'success' | 'error', message: string } | null>(null);
|
||||
const [testErrorLogOpen, setTestErrorLogOpen] = useState(false);
|
||||
@@ -1061,6 +1064,8 @@ const ConnectionModal: React.FC<{
|
||||
setRedisDbList([]);
|
||||
setMongoMembers([]);
|
||||
setUriFeedback(null);
|
||||
setCustomIconType(undefined);
|
||||
setCustomIconColor(undefined);
|
||||
setTypeSelectWarning(null);
|
||||
setDriverStatusLoaded(false);
|
||||
void refreshDriverStatus();
|
||||
@@ -1146,6 +1151,8 @@ const ConnectionModal: React.FC<{
|
||||
mongoReplicaPassword: config.mongoReplicaPassword || ''
|
||||
});
|
||||
setUseSSL(!!config.useSSL);
|
||||
setCustomIconType(initialValues.iconType);
|
||||
setCustomIconColor(initialValues.iconColor);
|
||||
setUseSSH(config.useSSH || false);
|
||||
setUseProxy(hasProxy);
|
||||
setUseHttpTunnel(hasHttpTunnel);
|
||||
@@ -1212,7 +1219,9 @@ const ConnectionModal: React.FC<{
|
||||
name: values.name || (isFileDatabaseType(values.type) ? (values.type === 'duckdb' ? 'DuckDB DB' : 'SQLite DB') : (values.type === 'redis' ? `Redis ${displayHost}` : displayHost)),
|
||||
config: config,
|
||||
includeDatabases: values.includeDatabases,
|
||||
includeRedisDatabases: isRedisType ? values.includeRedisDatabases : undefined
|
||||
includeRedisDatabases: isRedisType ? values.includeRedisDatabases : undefined,
|
||||
iconType: customIconType,
|
||||
iconColor: customIconColor,
|
||||
};
|
||||
|
||||
if (initialValues) {
|
||||
@@ -1735,32 +1744,32 @@ const ConnectionModal: React.FC<{
|
||||
|
||||
const dbTypeGroups = [
|
||||
{ label: '关系型数据库', items: [
|
||||
{ key: 'mysql', name: 'MySQL', icon: <ConsoleSqlOutlined style={{ fontSize: 24, color: '#00758F' }} /> },
|
||||
{ key: 'mariadb', name: 'MariaDB', icon: <ConsoleSqlOutlined style={{ fontSize: 24, color: '#003545' }} /> },
|
||||
{ key: 'diros', name: 'Doris', icon: <ConsoleSqlOutlined style={{ fontSize: 24, color: '#0050b3' }} /> },
|
||||
{ key: 'sphinx', name: 'Sphinx', icon: <ConsoleSqlOutlined style={{ fontSize: 24, color: '#2F5D62' }} /> },
|
||||
{ key: 'clickhouse', name: 'ClickHouse', icon: <DatabaseOutlined style={{ fontSize: 24, color: '#FFCC01' }} /> },
|
||||
{ key: 'postgres', name: 'PostgreSQL', icon: <DatabaseOutlined style={{ fontSize: 24, color: '#336791' }} /> },
|
||||
{ key: 'sqlserver', name: 'SQL Server', icon: <DatabaseOutlined style={{ fontSize: 24, color: '#CC2927' }} /> },
|
||||
{ key: 'sqlite', name: 'SQLite', icon: <FileTextOutlined style={{ fontSize: 24, color: '#003B57' }} /> },
|
||||
{ key: 'duckdb', name: 'DuckDB', icon: <FileTextOutlined style={{ fontSize: 24, color: '#f59e0b' }} /> },
|
||||
{ key: 'oracle', name: 'Oracle', icon: <DatabaseOutlined style={{ fontSize: 24, color: '#F80000' }} /> },
|
||||
{ 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: '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: '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: 'dameng', name: 'Dameng (达梦)', icon: <CloudServerOutlined style={{ fontSize: 24, color: '#1890ff' }} /> },
|
||||
{ key: 'kingbase', name: 'Kingbase (人大金仓)', icon: <DatabaseOutlined style={{ fontSize: 24, color: '#faad14' }} /> },
|
||||
{ key: 'highgo', name: 'HighGo (瀚高)', icon: <DatabaseOutlined style={{ fontSize: 24, color: '#00a854' }} /> },
|
||||
{ key: 'vastbase', name: 'Vastbase (海量)', icon: <DatabaseOutlined style={{ fontSize: 24, color: '#1a6dff' }} /> },
|
||||
{ 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) },
|
||||
]},
|
||||
{ label: 'NoSQL', items: [
|
||||
{ key: 'mongodb', name: 'MongoDB', icon: <CloudServerOutlined style={{ fontSize: 24, color: '#47A248' }} /> },
|
||||
{ key: 'redis', name: 'Redis', icon: <CloudOutlined style={{ fontSize: 24, color: '#DC382D' }} /> },
|
||||
{ key: 'mongodb', name: 'MongoDB', icon: getDbIcon('mongodb', undefined, 36) },
|
||||
{ key: 'redis', name: 'Redis', icon: getDbIcon('redis', undefined, 36) },
|
||||
]},
|
||||
{ label: '时序数据库', items: [
|
||||
{ key: 'tdengine', name: 'TDengine', icon: <DatabaseOutlined style={{ fontSize: 24, color: '#2F54EB' }} /> },
|
||||
{ key: 'tdengine', name: 'TDengine', icon: getDbIcon('tdengine', undefined, 36) },
|
||||
]},
|
||||
{ label: '其他', items: [
|
||||
{ key: 'custom', name: 'Custom (自定义)', icon: <AppstoreAddOutlined style={{ fontSize: 24, color: '#595959' }} /> },
|
||||
{ key: 'custom', name: 'Custom (自定义)', icon: getDbIcon('custom', undefined, 36) },
|
||||
]},
|
||||
];
|
||||
|
||||
@@ -2512,16 +2521,101 @@ const ConnectionModal: React.FC<{
|
||||
/>
|
||||
)}
|
||||
{(() => {
|
||||
const sectionItems: Array<{ key: 'basic' | 'network'; title: string; description: string; icon: React.ReactNode }> = [
|
||||
const sectionItems: Array<{ key: 'basic' | 'network' | 'appearance'; title: string; description: string; icon: React.ReactNode }> = [
|
||||
{ key: 'basic', title: '基础信息', description: '名称、地址、认证、URI 与数据库范围', icon: <DatabaseOutlined /> },
|
||||
...(!isCustom && !isFileDb ? [{ key: 'network' as const, title: '网络与安全', description: 'SSL、SSH、代理与高级连接', icon: <CloudOutlined /> }] : []),
|
||||
{ key: 'appearance', title: '外观', description: '自定义图标与颜色', icon: <BgColorsOutlined /> },
|
||||
];
|
||||
const resolvedSection = sectionItems.some((item) => item.key === activeConfigSection)
|
||||
? activeConfigSection
|
||||
: sectionItems[0]?.key || 'basic';
|
||||
|
||||
const effectiveIconType = customIconType || dbType;
|
||||
const effectiveIconColor = customIconColor || getDbDefaultColor(effectiveIconType);
|
||||
|
||||
const appearanceSection = (
|
||||
<div style={{ display: 'grid', gap: 18 }}>
|
||||
<div style={{ ...modalInnerSectionStyle, padding: 16 }}>
|
||||
<div style={{ marginBottom: 12, fontSize: 13, fontWeight: 700, color: darkMode ? '#f5f7ff' : '#162033' }}>图标</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
|
||||
{DB_ICON_TYPES.map((iconKey) => {
|
||||
const isActive = effectiveIconType === iconKey;
|
||||
return (
|
||||
<button
|
||||
key={iconKey}
|
||||
type="button"
|
||||
title={getDbIconLabel(iconKey)}
|
||||
onClick={() => setCustomIconType(iconKey === dbType ? undefined : iconKey)}
|
||||
style={{
|
||||
width: 44, height: 44, borderRadius: 10,
|
||||
display: 'grid', placeItems: 'center',
|
||||
border: `2px solid ${isActive ? effectiveIconColor : (darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.06)')}`,
|
||||
background: isActive
|
||||
? (darkMode ? 'rgba(255,255,255,0.08)' : 'rgba(24,144,255,0.06)')
|
||||
: 'transparent',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 120ms ease',
|
||||
}}
|
||||
>
|
||||
{getDbIcon(iconKey, isActive ? effectiveIconColor : undefined, 22)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div style={{ marginTop: 6, fontSize: 11, color: darkMode ? 'rgba(255,255,255,0.45)' : 'rgba(0,0,0,0.35)' }}>
|
||||
当前:{getDbIconLabel(effectiveIconType)}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ ...modalInnerSectionStyle, padding: 16 }}>
|
||||
<div style={{ marginBottom: 12, fontSize: 13, fontWeight: 700, color: darkMode ? '#f5f7ff' : '#162033' }}>颜色</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' }}>
|
||||
{PRESET_ICON_COLORS.map((presetColor) => {
|
||||
const isActive = effectiveIconColor === presetColor;
|
||||
return (
|
||||
<button
|
||||
key={presetColor}
|
||||
type="button"
|
||||
onClick={() => setCustomIconColor(presetColor === getDbDefaultColor(effectiveIconType) ? undefined : presetColor)}
|
||||
style={{
|
||||
width: 28, height: 28, borderRadius: 8,
|
||||
background: presetColor,
|
||||
border: isActive ? `2.5px solid ${darkMode ? '#fff' : '#162033'}` : '2px solid transparent',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 120ms ease',
|
||||
boxShadow: isActive ? `0 0 0 2px ${presetColor}40` : 'none',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<input
|
||||
type="color"
|
||||
value={effectiveIconColor}
|
||||
onChange={(e) => setCustomIconColor(e.target.value === getDbDefaultColor(effectiveIconType) ? undefined : e.target.value)}
|
||||
title="自定义颜色"
|
||||
style={{ width: 28, height: 28, border: 'none', padding: 0, cursor: 'pointer', borderRadius: 6, background: 'transparent' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ ...modalInnerSectionStyle, padding: 16, display: 'flex', alignItems: 'center', gap: 14 }}>
|
||||
<div style={{ fontSize: 13, fontWeight: 700, color: darkMode ? '#f5f7ff' : '#162033' }}>预览</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
|
||||
{getDbIcon(effectiveIconType, effectiveIconColor, 24)}
|
||||
<span style={{ fontSize: 14, color: darkMode ? '#e0e0e0' : '#333' }}>{form.getFieldValue('name') || '连接名称'}</span>
|
||||
</div>
|
||||
{(customIconType || customIconColor) && (
|
||||
<Button size="small" type="link" onClick={() => { setCustomIconType(undefined); setCustomIconColor(undefined); }}>
|
||||
重置为默认
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const currentSectionContent = resolvedSection === 'basic'
|
||||
? baseInfoSection
|
||||
: networkSecuritySection;
|
||||
: resolvedSection === 'appearance'
|
||||
? appearanceSection
|
||||
: networkSecuritySection;
|
||||
|
||||
if (sectionItems.length <= 1) {
|
||||
return currentSectionContent;
|
||||
|
||||
217
frontend/src/components/DatabaseIcons.tsx
Normal file
@@ -0,0 +1,217 @@
|
||||
import React from 'react';
|
||||
|
||||
// ─── 公共接口 ───────────────────────────────────────────────
|
||||
|
||||
export interface DbIconProps {
|
||||
size?: number;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
// ─── 默认色表 ───────────────────────────────────────────────
|
||||
|
||||
const DB_DEFAULT_COLORS: Record<string, string> = {
|
||||
mysql: '#00758F',
|
||||
mariadb: '#003545',
|
||||
postgres: '#336791',
|
||||
redis: '#DC382D',
|
||||
mongodb: '#47A248',
|
||||
kingbase: '#1890FF',
|
||||
dameng: '#E6002D',
|
||||
oracle: '#F80000',
|
||||
sqlserver: '#CC2927',
|
||||
clickhouse: '#FFBF00',
|
||||
sqlite: '#003B57',
|
||||
duckdb: '#FFC107',
|
||||
vastbase: '#0066CC',
|
||||
highgo: '#00A86B',
|
||||
tdengine: '#2962FF',
|
||||
diros: '#0050B3',
|
||||
sphinx: '#2F5D62',
|
||||
custom: '#888888',
|
||||
};
|
||||
|
||||
export const getDbDefaultColor = (type: string): string =>
|
||||
DB_DEFAULT_COLORS[type?.toLowerCase()] || DB_DEFAULT_COLORS.custom;
|
||||
|
||||
// ─── 有品牌 SVG 文件的数据库类型(文件在 /db-icons/ 下) ────
|
||||
|
||||
const BRAND_SVG_TYPES = new Set([
|
||||
'mysql', 'mariadb', 'postgres', 'redis', 'mongodb', 'clickhouse', 'sqlite',
|
||||
'diros', 'sphinx', 'duckdb',
|
||||
]);
|
||||
|
||||
/** 品牌 SVG 图标:用 <img> 加载 /db-icons/*.svg */
|
||||
const BrandSvgIcon: React.FC<{ type: string; size: number; color?: string }> = ({ type, size, color }) => {
|
||||
const bgColor = color || getDbDefaultColor(type);
|
||||
return (
|
||||
<span style={{
|
||||
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
|
||||
width: size, height: size, borderRadius: size * 0.22,
|
||||
background: '#fff', border: `1.5px solid ${bgColor}`,
|
||||
flexShrink: 0, overflow: 'hidden',
|
||||
}}>
|
||||
<img
|
||||
src={`/db-icons/${type}.svg`}
|
||||
alt={type}
|
||||
width={size * 0.7}
|
||||
height={size * 0.7}
|
||||
style={{ display: 'block' }}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
// ─── 彩色标签图标(fallback) ──────────────────────────────
|
||||
|
||||
/** 通用彩色标签:填充背景 + 白色粗体缩写 */
|
||||
const ColorBadge: React.FC<{ size: number; color: string; label: string }> = ({ size, color, label }) => {
|
||||
const textSize = label.length <= 2 ? size * 0.48 : size * 0.38;
|
||||
return (
|
||||
<svg width={size} height={size} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1" y="1" width="22" height="22" rx="5" fill={color}/>
|
||||
<text
|
||||
x="12" y="12" dominantBaseline="central" textAnchor="middle"
|
||||
fontSize={textSize} fontWeight="800" fontFamily="system-ui,-apple-system,sans-serif"
|
||||
fill="#fff" letterSpacing={label.length > 2 ? -0.5 : 0}
|
||||
>
|
||||
{label}
|
||||
</text>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
// ─── 各数据库图标 ───────────────────────────────────────────
|
||||
|
||||
// 有品牌 SVG 的数据库
|
||||
const MySQLIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<BrandSvgIcon type="mysql" size={size} color={color} />
|
||||
);
|
||||
const MariaDBIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<BrandSvgIcon type="mariadb" size={size} color={color} />
|
||||
);
|
||||
const PostgresIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<BrandSvgIcon type="postgres" size={size} color={color} />
|
||||
);
|
||||
const RedisIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<BrandSvgIcon type="redis" size={size} color={color} />
|
||||
);
|
||||
const MongoDBIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<BrandSvgIcon type="mongodb" size={size} color={color} />
|
||||
);
|
||||
const ClickHouseIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<BrandSvgIcon type="clickhouse" size={size} color={color} />
|
||||
);
|
||||
const SQLiteIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<BrandSvgIcon type="sqlite" size={size} color={color} />
|
||||
);
|
||||
|
||||
// 无品牌 SVG → 彩色文字标签
|
||||
const OracleIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.oracle} label="Or" />
|
||||
);
|
||||
const SQLServerIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.sqlserver} label="SS" />
|
||||
);
|
||||
const DorisIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<BrandSvgIcon type="diros" size={size} color={color} />
|
||||
);
|
||||
const SphinxIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<BrandSvgIcon type="sphinx" size={size} color={color} />
|
||||
);
|
||||
const DuckDBIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<BrandSvgIcon type="duckdb" size={size} color={color} />
|
||||
);
|
||||
const KingBaseIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.kingbase} label="KB" />
|
||||
);
|
||||
const DamengIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.dameng} label="DM" />
|
||||
);
|
||||
const VastBaseIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.vastbase} label="VB" />
|
||||
);
|
||||
const HighGoIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.highgo} label="HG" />
|
||||
);
|
||||
const TDengineIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.tdengine} label="TD" />
|
||||
);
|
||||
|
||||
/** Custom — 齿轮图标 */
|
||||
const CustomIcon: React.FC<DbIconProps> = ({ size = 16, color }) => {
|
||||
const c = color || DB_DEFAULT_COLORS.custom;
|
||||
return (
|
||||
<svg width={size} height={size} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1" y="1" width="22" height="22" rx="5" fill={c}/>
|
||||
<circle cx="12" cy="12" r="3.5" stroke="#fff" strokeWidth="1.5" fill="none"/>
|
||||
<path d="M12 4v2.5M12 17.5V20M4 12h2.5M17.5 12H20M6.34 6.34l1.77 1.77M15.89 15.89l1.77 1.77M6.34 17.66l1.77-1.77M15.89 8.11l1.77-1.77" stroke="#fff" strokeWidth="1.3" strokeLinecap="round"/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
// ─── 图标注册表 ─────────────────────────────────────────────
|
||||
|
||||
const DorisIconFallback: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.diros} label="Do" />
|
||||
);
|
||||
const SphinxIconFallback: React.FC<DbIconProps> = ({ size = 16, color }) => (
|
||||
<ColorBadge size={size} color={color || DB_DEFAULT_COLORS.sphinx} label="Sp" />
|
||||
);
|
||||
|
||||
const DB_ICON_MAP: Record<string, React.FC<DbIconProps>> = {
|
||||
mysql: MySQLIcon,
|
||||
mariadb: MariaDBIcon,
|
||||
diros: DorisIcon,
|
||||
sphinx: SphinxIcon,
|
||||
postgres: PostgresIcon,
|
||||
redis: RedisIcon,
|
||||
mongodb: MongoDBIcon,
|
||||
kingbase: KingBaseIcon,
|
||||
dameng: DamengIcon,
|
||||
oracle: OracleIcon,
|
||||
sqlserver: SQLServerIcon,
|
||||
clickhouse: ClickHouseIcon,
|
||||
sqlite: SQLiteIcon,
|
||||
duckdb: DuckDBIcon,
|
||||
vastbase: VastBaseIcon,
|
||||
highgo: HighGoIcon,
|
||||
tdengine: TDengineIcon,
|
||||
custom: CustomIcon,
|
||||
};
|
||||
|
||||
/** 可选图标类型列表(用于图标选择器 UI) */
|
||||
export const DB_ICON_TYPES: string[] = [
|
||||
'mysql', 'mariadb', 'postgres', 'redis', 'mongodb',
|
||||
'oracle', 'sqlserver', 'sqlite', 'duckdb', 'clickhouse',
|
||||
'kingbase', 'dameng', 'vastbase', 'highgo', 'tdengine', 'custom',
|
||||
];
|
||||
|
||||
/** 该类型是否有品牌 SVG 文件 */
|
||||
export const hasBrandSvg = (type: string): boolean => BRAND_SVG_TYPES.has(type?.toLowerCase());
|
||||
|
||||
/** 获取数据库图标 React 节点 */
|
||||
export const getDbIcon = (type: string, color?: string, size?: number): React.ReactNode => {
|
||||
const key = (type || 'custom').toLowerCase();
|
||||
const Component = DB_ICON_MAP[key] || CustomIcon;
|
||||
return <Component size={size} color={color} />;
|
||||
};
|
||||
|
||||
/** 获取数据库图标显示名称(中文) */
|
||||
export const getDbIconLabel = (type: string): string => {
|
||||
const labels: Record<string, string> = {
|
||||
mysql: 'MySQL', mariadb: 'MariaDB', postgres: 'PostgreSQL',
|
||||
redis: 'Redis', mongodb: 'MongoDB', oracle: 'Oracle',
|
||||
sqlserver: 'SQL Server', clickhouse: 'ClickHouse', sqlite: 'SQLite',
|
||||
duckdb: 'DuckDB', kingbase: '金仓', dameng: '达梦',
|
||||
vastbase: 'VastBase', highgo: '瀚高', tdengine: 'TDengine',
|
||||
custom: '自定义',
|
||||
};
|
||||
return labels[type?.toLowerCase()] || type;
|
||||
};
|
||||
|
||||
/** 预设颜色列表 */
|
||||
export const PRESET_ICON_COLORS: string[] = [
|
||||
'#336791', '#00758F', '#DC382D', '#47A248', '#F80000',
|
||||
'#CC2927', '#1890FF', '#E6002D', '#FFBF00', '#2962FF',
|
||||
'#00A86B', '#0066CC', '#FF6B35', '#7C3AED',
|
||||
];
|
||||
@@ -35,6 +35,7 @@ import { Tree, message, Dropdown, MenuProps, Input, Button, Modal, Form, Badge,
|
||||
import { useStore } from '../store';
|
||||
import { buildOverlayWorkbenchTheme } from '../utils/overlayWorkbenchTheme';
|
||||
import { SavedConnection } from '../types';
|
||||
import { getDbIcon } from './DatabaseIcons';
|
||||
import { DBGetDatabases, DBGetTables, DBQuery, DBShowCreateTable, ExportTable, OpenSQLFile, ExecuteSQLFile, CancelSQLFileExecution, CreateDatabase, RenameDatabase, DropDatabase, RenameTable, DropTable, DropView, DropFunction, RenameView } from '../../wailsjs/go/app/App';
|
||||
import { EventsOn } from '../../wailsjs/runtime/runtime';
|
||||
import { normalizeOpacityForPlatform, resolveAppearanceValues } from '../utils/appearance';
|
||||
@@ -329,7 +330,7 @@ const Sidebar: React.FC<{ onEditConnection?: (conn: SavedConnection) => void }>
|
||||
return {
|
||||
title: conn.name,
|
||||
key: conn.id,
|
||||
icon: conn.config.type === 'redis' ? <CloudOutlined style={{ color: '#DC382D' }} /> : <HddOutlined />,
|
||||
icon: getDbIcon(conn.iconType || conn.config.type, conn.iconColor, 22),
|
||||
type: 'connection',
|
||||
dataRef: conn,
|
||||
isLeaf: false,
|
||||
@@ -3603,7 +3604,7 @@ const Sidebar: React.FC<{ onEditConnection?: (conn: SavedConnection) => void }>
|
||||
}
|
||||
|
||||
const statusBadge = node.type === 'connection' || node.type === 'database' ? (
|
||||
<Badge status={status} style={{ marginRight: 8 }} />
|
||||
<Badge status={status} style={{ marginLeft: 4, marginRight: 8 }} />
|
||||
) : null;
|
||||
|
||||
const displayTitle = String(node.title ?? '');
|
||||
|
||||
@@ -72,6 +72,8 @@ export interface SavedConnection {
|
||||
config: ConnectionConfig;
|
||||
includeDatabases?: string[];
|
||||
includeRedisDatabases?: number[]; // Redis databases to show (0-15)
|
||||
iconType?: string; // 自定义图标类型(如 'mysql','postgres'),不填则取 config.type
|
||||
iconColor?: string; // 自定义图标颜色(十六进制),不填则取类型默认色
|
||||
}
|
||||
|
||||
export interface ConnectionTag {
|
||||
|
||||
@@ -4,9 +4,15 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"GoNavi-Wails/internal/logger"
|
||||
)
|
||||
|
||||
var damengDatabaseQueries = []string{
|
||||
// 优先使用达梦原生系统表
|
||||
"SELECT DISTINCT OBJECT_NAME AS DATABASE_NAME FROM SYS.SYSOBJECTS WHERE TYPE$ = 'SCH' AND OBJECT_NAME NOT IN ('SYS','SYSDBA','SYSAUDITOR','SYSSSO','CTISYS','__RECYCLE_USER__') ORDER BY OBJECT_NAME",
|
||||
"SELECT SCHEMA_NAME AS DATABASE_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('SYS','SYSDBA','SYSAUDITOR','SYSSSO','CTISYS','INFORMATION_SCHEMA') ORDER BY SCHEMA_NAME",
|
||||
// Oracle 兼容层
|
||||
"SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') AS DATABASE_NAME FROM DUAL",
|
||||
"SELECT SYS_CONTEXT('USERENV', 'CURRENT_USER') AS DATABASE_NAME FROM DUAL",
|
||||
"SELECT USERNAME AS DATABASE_NAME FROM USER_USERS",
|
||||
@@ -24,12 +30,14 @@ func collectDamengDatabaseNames(query damengQueryFunc) ([]string, error) {
|
||||
dbs := make([]string, 0, 64)
|
||||
var lastErr error
|
||||
|
||||
for _, q := range damengDatabaseQueries {
|
||||
for idx, q := range damengDatabaseQueries {
|
||||
data, _, err := query(q)
|
||||
if err != nil {
|
||||
logger.Warnf("达梦 GetDatabases 查询[%d]失败:%v(SQL: %.80s…)", idx, err, q)
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
newCount := 0
|
||||
for _, row := range data {
|
||||
name := getDamengRowString(row,
|
||||
"DATABASE_NAME",
|
||||
@@ -58,10 +66,14 @@ func collectDamengDatabaseNames(query damengQueryFunc) ([]string, error) {
|
||||
}
|
||||
seen[key] = struct{}{}
|
||||
dbs = append(dbs, name)
|
||||
newCount++
|
||||
}
|
||||
logger.Infof("达梦 GetDatabases 查询[%d]成功:返回 %d 行,新增 %d 条(SQL: %.80s…)", idx, len(data), newCount, q)
|
||||
}
|
||||
|
||||
logger.Infof("达梦 GetDatabases 最终结果:共 %d 条数据库/schema", len(dbs))
|
||||
if len(dbs) == 0 && lastErr != nil {
|
||||
logger.Warnf("达梦 GetDatabases 所有查询均失败,返回最后错误:%v", lastErr)
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
|
||||