diff --git a/frontend/public/db-icons/chroma.svg b/frontend/public/db-icons/chroma.svg index 1a22d29..0d190a4 100644 --- a/frontend/public/db-icons/chroma.svg +++ b/frontend/public/db-icons/chroma.svg @@ -1,7 +1 @@ - - Chroma - - - - - + diff --git a/frontend/public/db-icons/dameng.png b/frontend/public/db-icons/dameng.png new file mode 100644 index 0000000..ba44acb Binary files /dev/null and b/frontend/public/db-icons/dameng.png differ diff --git a/frontend/public/db-icons/gaussdb.ico b/frontend/public/db-icons/gaussdb.ico new file mode 100644 index 0000000..bd9490b Binary files /dev/null and b/frontend/public/db-icons/gaussdb.ico differ diff --git a/frontend/public/db-icons/gaussdb.svg b/frontend/public/db-icons/gaussdb.svg deleted file mode 100644 index a43e8fa..0000000 --- a/frontend/public/db-icons/gaussdb.svg +++ /dev/null @@ -1,7 +0,0 @@ - - GaussDB - - - - - diff --git a/frontend/public/db-icons/goldendb.ico b/frontend/public/db-icons/goldendb.ico new file mode 100644 index 0000000..74d3adb Binary files /dev/null and b/frontend/public/db-icons/goldendb.ico differ diff --git a/frontend/public/db-icons/goldendb.svg b/frontend/public/db-icons/goldendb.svg deleted file mode 100644 index 72df461..0000000 --- a/frontend/public/db-icons/goldendb.svg +++ /dev/null @@ -1,6 +0,0 @@ - - GoldenDB - - - - diff --git a/frontend/public/db-icons/highgo.ico b/frontend/public/db-icons/highgo.ico new file mode 100644 index 0000000..5a56dc0 Binary files /dev/null and b/frontend/public/db-icons/highgo.ico differ diff --git a/frontend/public/db-icons/iotdb.svg b/frontend/public/db-icons/iotdb.svg index 4d1b940..d742630 100644 --- a/frontend/public/db-icons/iotdb.svg +++ b/frontend/public/db-icons/iotdb.svg @@ -1,7 +1,57 @@ - - Apache IoTDB - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/db-icons/iris.png b/frontend/public/db-icons/iris.png new file mode 100644 index 0000000..048b311 Binary files /dev/null and b/frontend/public/db-icons/iris.png differ diff --git a/frontend/public/db-icons/jvm.ico b/frontend/public/db-icons/jvm.ico new file mode 100644 index 0000000..c6b6979 Binary files /dev/null and b/frontend/public/db-icons/jvm.ico differ diff --git a/frontend/public/db-icons/kafka.png b/frontend/public/db-icons/kafka.png new file mode 100644 index 0000000..a4b5359 Binary files /dev/null and b/frontend/public/db-icons/kafka.png differ diff --git a/frontend/public/db-icons/kafka.svg b/frontend/public/db-icons/kafka.svg deleted file mode 100644 index 7bc2988..0000000 --- a/frontend/public/db-icons/kafka.svg +++ /dev/null @@ -1,11 +0,0 @@ - - Kafka - - - - - - - - - diff --git a/frontend/public/db-icons/kingbase.ico b/frontend/public/db-icons/kingbase.ico new file mode 100644 index 0000000..b1f280c Binary files /dev/null and b/frontend/public/db-icons/kingbase.ico differ diff --git a/frontend/public/db-icons/mqtt.svg b/frontend/public/db-icons/mqtt.svg index f82a854..20fe3d6 100644 --- a/frontend/public/db-icons/mqtt.svg +++ b/frontend/public/db-icons/mqtt.svg @@ -1,9 +1,35 @@ - - MQTT - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/db-icons/oceanbase.png b/frontend/public/db-icons/oceanbase.png new file mode 100644 index 0000000..9d43ce8 Binary files /dev/null and b/frontend/public/db-icons/oceanbase.png differ diff --git a/frontend/public/db-icons/opengauss.ico b/frontend/public/db-icons/opengauss.ico new file mode 100644 index 0000000..aec5a87 Binary files /dev/null and b/frontend/public/db-icons/opengauss.ico differ diff --git a/frontend/public/db-icons/oracle.ico b/frontend/public/db-icons/oracle.ico new file mode 100644 index 0000000..c59864b Binary files /dev/null and b/frontend/public/db-icons/oracle.ico differ diff --git a/frontend/public/db-icons/qdrant.svg b/frontend/public/db-icons/qdrant.svg index 8e26bb2..c10ad96 100644 --- a/frontend/public/db-icons/qdrant.svg +++ b/frontend/public/db-icons/qdrant.svg @@ -1,7 +1,35 @@ - - Qdrant - - - - - + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/public/db-icons/rocketmq.png b/frontend/public/db-icons/rocketmq.png new file mode 100644 index 0000000..7a70ce7 Binary files /dev/null and b/frontend/public/db-icons/rocketmq.png differ diff --git a/frontend/public/db-icons/rocketmq.svg b/frontend/public/db-icons/rocketmq.svg deleted file mode 100644 index a5dec65..0000000 --- a/frontend/public/db-icons/rocketmq.svg +++ /dev/null @@ -1,6 +0,0 @@ - - RocketMQ - - - - diff --git a/frontend/public/db-icons/starrocks.png b/frontend/public/db-icons/starrocks.png new file mode 100644 index 0000000..a41cbb7 Binary files /dev/null and b/frontend/public/db-icons/starrocks.png differ diff --git a/frontend/public/db-icons/tdengine.ico b/frontend/public/db-icons/tdengine.ico new file mode 100644 index 0000000..1918d15 Binary files /dev/null and b/frontend/public/db-icons/tdengine.ico differ diff --git a/frontend/public/db-icons/vastbase.svg b/frontend/public/db-icons/vastbase.svg new file mode 100644 index 0000000..370d089 --- /dev/null +++ b/frontend/public/db-icons/vastbase.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/components/DatabaseIcons.test.tsx b/frontend/src/components/DatabaseIcons.test.tsx index d74a57a..ed9afbd 100644 --- a/frontend/src/components/DatabaseIcons.test.tsx +++ b/frontend/src/components/DatabaseIcons.test.tsx @@ -4,91 +4,40 @@ import { renderToStaticMarkup } from 'react-dom/server'; import { DB_ICON_TYPES, getDbIcon, getDbIconLabel } from './DatabaseIcons'; +const BRAND_ICON_CASES: Array<[string, string, string]> = [ + ['elasticsearch', 'Elasticsearch', 'elasticsearch.svg'], + ['oceanbase', 'OceanBase', 'oceanbase.png'], + ['oracle', 'Oracle', 'oracle.ico'], + ['starrocks', 'StarRocks', 'starrocks.png'], + ['kingbase', '金仓', 'kingbase.ico'], + ['dameng', '达梦', 'dameng.png'], + ['vastbase', 'VastBase', 'vastbase.svg'], + ['opengauss', 'OpenGauss', 'opengauss.ico'], + ['gaussdb', 'GaussDB', 'gaussdb.ico'], + ['goldendb', 'GoldenDB', 'goldendb.ico'], + ['highgo', '瀚高', 'highgo.ico'], + ['iris', 'InterSystems IRIS', 'iris.png'], + ['tdengine', 'TDengine', 'tdengine.ico'], + ['iotdb', 'Apache IoTDB', 'iotdb.svg'], + ['rocketmq', 'RocketMQ', 'rocketmq.png'], + ['mqtt', 'MQTT', 'mqtt.svg'], + ['kafka', 'Kafka', 'kafka.png'], + ['rabbitmq', 'RabbitMQ', 'rabbitmq.svg'], + ['chroma', 'Chroma', 'chroma.svg'], + ['qdrant', 'Qdrant', 'qdrant.svg'], + ['jvm', 'JVM', 'jvm.ico'], +]; + describe('DatabaseIcons', () => { - it('includes InterSystems IRIS in the selectable database icons', () => { - expect(DB_ICON_TYPES).toContain('iris'); - expect(getDbIconLabel('iris')).toBe('InterSystems IRIS'); - }); - - it('includes Elasticsearch in the selectable database icons', () => { - expect(DB_ICON_TYPES).toContain('elasticsearch'); - expect(getDbIconLabel('elasticsearch')).toBe('Elasticsearch'); - const markup = renderToStaticMarkup(<>{getDbIcon('elasticsearch', undefined, 22)}); - expect(markup).toContain('elasticsearch.svg'); - expect(markup).toContain('alt="elasticsearch"'); - }); - - it('includes Chroma in the selectable database icons', () => { - expect(DB_ICON_TYPES).toContain('chroma'); - expect(getDbIconLabel('chroma')).toBe('Chroma'); - const markup = renderToStaticMarkup(<>{getDbIcon('chroma', undefined, 22)}); - expect(markup).toContain('chroma.svg'); - expect(markup).toContain('alt="chroma"'); - }); - - it('includes Qdrant in the selectable database icons', () => { - expect(DB_ICON_TYPES).toContain('qdrant'); - expect(getDbIconLabel('qdrant')).toBe('Qdrant'); - const markup = renderToStaticMarkup(<>{getDbIcon('qdrant', undefined, 22)}); - expect(markup).toContain('qdrant.svg'); - expect(markup).toContain('alt="qdrant"'); - }); - - it('includes Apache IoTDB in the selectable database icons', () => { - expect(DB_ICON_TYPES).toContain('iotdb'); - expect(getDbIconLabel('iotdb')).toBe('Apache IoTDB'); - const markup = renderToStaticMarkup(<>{getDbIcon('iotdb', undefined, 22)}); - expect(markup).toContain('iotdb.svg'); - expect(markup).toContain('alt="iotdb"'); - }); - - it('includes RocketMQ in the selectable database icons', () => { - expect(DB_ICON_TYPES).toContain('rocketmq'); - expect(getDbIconLabel('rocketmq')).toBe('RocketMQ'); - const markup = renderToStaticMarkup(<>{getDbIcon('rocketmq', undefined, 22)}); - expect(markup).toContain('rocketmq.svg'); - expect(markup).toContain('alt="rocketmq"'); - }); - - it('includes MQTT in the selectable database icons', () => { - expect(DB_ICON_TYPES).toContain('mqtt'); - expect(getDbIconLabel('mqtt')).toBe('MQTT'); - const markup = renderToStaticMarkup(<>{getDbIcon('mqtt', undefined, 22)}); - expect(markup).toContain('mqtt.svg'); - expect(markup).toContain('alt="mqtt"'); - }); - - it('includes Kafka in the selectable database icons', () => { - expect(DB_ICON_TYPES).toContain('kafka'); - expect(getDbIconLabel('kafka')).toBe('Kafka'); - const markup = renderToStaticMarkup(<>{getDbIcon('kafka', undefined, 22)}); - expect(markup).toContain('kafka.svg'); - expect(markup).toContain('alt="kafka"'); - }); - - it('includes RabbitMQ in the selectable database icons', () => { - expect(DB_ICON_TYPES).toContain('rabbitmq'); - expect(getDbIconLabel('rabbitmq')).toBe('RabbitMQ'); - const markup = renderToStaticMarkup(<>{getDbIcon('rabbitmq', undefined, 22)}); - expect(markup).toContain('rabbitmq.svg'); - expect(markup).toContain('alt="rabbitmq"'); - }); - - it('includes GaussDB in the selectable database icons', () => { - expect(DB_ICON_TYPES).toContain('gaussdb'); - expect(getDbIconLabel('gaussdb')).toBe('GaussDB'); - const markup = renderToStaticMarkup(<>{getDbIcon('gaussdb', undefined, 22)}); - expect(markup).toContain('gaussdb.svg'); - expect(markup).toContain('alt="gaussdb"'); - }); - - it('includes GoldenDB in the selectable database icons', () => { - expect(DB_ICON_TYPES).toContain('goldendb'); - expect(getDbIconLabel('goldendb')).toBe('GoldenDB'); - const markup = renderToStaticMarkup(<>{getDbIcon('goldendb', undefined, 22)}); - expect(markup).toContain('goldendb.svg'); - expect(markup).toContain('alt="goldendb"'); - }); + for (const [type, label, asset] of BRAND_ICON_CASES) { + it(`includes ${label} in the selectable database icons`, () => { + expect(DB_ICON_TYPES).toContain(type); + expect(getDbIconLabel(type)).toBe(label); + const markup = renderToStaticMarkup(<>{getDbIcon(type, undefined, 22)}); + expect(markup).toContain(asset); + expect(markup).toContain(`alt="${type}"`); + }); + } it('wraps database icons in a consistent frame for sidebar sizing', () => { const mysqlMarkup = renderToStaticMarkup(<>{getDbIcon('mysql', undefined, 22)}); diff --git a/frontend/src/components/DatabaseIcons.tsx b/frontend/src/components/DatabaseIcons.tsx index 0cc8696..126a820 100644 --- a/frontend/src/components/DatabaseIcons.tsx +++ b/frontend/src/components/DatabaseIcons.tsx @@ -67,31 +67,90 @@ const DB_DEFAULT_COLORS: Record = { export const getDbDefaultColor = (type: string): string => DB_DEFAULT_COLORS[type?.toLowerCase()] || DB_DEFAULT_COLORS.custom; -// ─── 有品牌 SVG 文件的数据库类型(文件在 /db-icons/ 下) ──── +type BrandAssetConfig = { + background?: string; + borderColor?: string; + iconScale?: number; + src: string; +}; -const BRAND_SVG_TYPES = new Set([ - 'mysql', 'mariadb', 'postgres', 'redis', 'mongodb', 'clickhouse', 'sqlite', - 'diros', 'sphinx', 'duckdb', 'sqlserver', 'elasticsearch', - 'gaussdb', 'goldendb', 'iotdb', 'rocketmq', 'mqtt', 'kafka', 'rabbitmq', - 'chroma', 'qdrant', -]); +// ─── 官方品牌资源(文件在 /db-icons/ 下) ──────────────────── -/** 品牌 SVG 图标:用 加载 /db-icons/*.svg */ -const BrandSvgIcon: React.FC<{ type: string; size: number; color?: string }> = ({ type, size, color }) => { - const bgColor = color || getDbDefaultColor(type); +const BRAND_ASSET_CONFIGS: Record = { + mysql: { src: '/db-icons/mysql.svg' }, + mariadb: { src: '/db-icons/mariadb.svg' }, + oceanbase: { src: '/db-icons/oceanbase.png', iconScale: 0.72 }, + postgres: { src: '/db-icons/postgres.svg' }, + redis: { src: '/db-icons/redis.svg' }, + mongodb: { src: '/db-icons/mongodb.svg' }, + elasticsearch: { src: '/db-icons/elasticsearch.svg' }, + jvm: { src: '/db-icons/jvm.ico', iconScale: 0.72 }, + kingbase: { src: '/db-icons/kingbase.ico', iconScale: 0.72 }, + dameng: { src: '/db-icons/dameng.png', iconScale: 0.72 }, + oracle: { src: '/db-icons/oracle.ico', iconScale: 0.72 }, + sqlserver: { src: '/db-icons/sqlserver.svg' }, + clickhouse: { src: '/db-icons/clickhouse.svg' }, + sqlite: { src: '/db-icons/sqlite.svg' }, + duckdb: { src: '/db-icons/duckdb.svg' }, + vastbase: { src: '/db-icons/vastbase.svg', iconScale: 0.84 }, + opengauss: { src: '/db-icons/opengauss.ico', iconScale: 0.72 }, + gaussdb: { src: '/db-icons/gaussdb.ico', iconScale: 0.72 }, + goldendb: { src: '/db-icons/goldendb.ico', iconScale: 0.72 }, + highgo: { src: '/db-icons/highgo.ico', iconScale: 0.72 }, + iris: { src: '/db-icons/iris.png', iconScale: 0.72 }, + tdengine: { src: '/db-icons/tdengine.ico', iconScale: 0.72 }, + iotdb: { + src: '/db-icons/iotdb.svg', + background: '#0F766E', + borderColor: '#0F766E', + iconScale: 0.82, + }, + rocketmq: { + src: '/db-icons/rocketmq.png', + background: '#0F172A', + borderColor: '#EA580C', + iconScale: 0.84, + }, + mqtt: { + src: '/db-icons/mqtt.svg', + background: '#0F172A', + borderColor: '#0EA5A4', + iconScale: 0.84, + }, + kafka: { src: '/db-icons/kafka.png', iconScale: 0.8 }, + rabbitmq: { src: '/db-icons/rabbitmq.svg', iconScale: 0.74 }, + chroma: { src: '/db-icons/chroma.svg', iconScale: 0.9 }, + qdrant: { src: '/db-icons/qdrant.svg', iconScale: 0.74 }, + diros: { src: '/db-icons/diros.svg' }, + starrocks: { + src: '/db-icons/starrocks.png', + background: '#0B1021', + borderColor: '#00A6A6', + iconScale: 0.84, + }, + sphinx: { src: '/db-icons/sphinx.svg' }, +}; + +const BRAND_ASSET_TYPES = new Set(Object.keys(BRAND_ASSET_CONFIGS)); + +/** 品牌图标:用 加载官方 svg/png/ico 资源 */ +const BrandAssetIcon: React.FC<{ type: string; size: number; color?: string }> = ({ type, size, color }) => { + const config = BRAND_ASSET_CONFIGS[type.toLowerCase()]; + const bgColor = color || config?.borderColor || getDbDefaultColor(type); + const iconScale = config?.iconScale ?? 0.64; return ( {type} @@ -99,128 +158,105 @@ const BrandSvgIcon: React.FC<{ type: string; size: number; color?: string }> = ( ); }; -// ─── 彩色标签图标(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 ( - - - - 2 ? -0.5 : 0} - > - {label} - - - - ); -}; - // ─── 各数据库图标 ─────────────────────────────────────────── -// 有品牌 SVG 的数据库 +// 有品牌官方资源的数据库 const MySQLIcon: React.FC = ({ size = 16, color }) => ( - + ); const MariaDBIcon: React.FC = ({ size = 16, color }) => ( - + ); const OceanBaseIcon: React.FC = ({ size = 16, color }) => ( - + ); const PostgresIcon: React.FC = ({ size = 16, color }) => ( - + ); const RedisIcon: React.FC = ({ size = 16, color }) => ( - + ); const MongoDBIcon: React.FC = ({ size = 16, color }) => ( - + ); const ClickHouseIcon: React.FC = ({ size = 16, color }) => ( - + ); const SQLiteIcon: React.FC = ({ size = 16, color }) => ( - + ); -// 无品牌 SVG → 彩色文字标签 const OracleIcon: React.FC = ({ size = 16, color }) => ( - + ); const SQLServerIcon: React.FC = ({ size = 16, color }) => ( - + ); const DorisIcon: React.FC = ({ size = 16, color }) => ( - + ); const StarRocksIcon: React.FC = ({ size = 16, color }) => ( - + ); const SphinxIcon: React.FC = ({ size = 16, color }) => ( - + ); const DuckDBIcon: React.FC = ({ size = 16, color }) => ( - + ); const KingBaseIcon: React.FC = ({ size = 16, color }) => ( - + ); const DamengIcon: React.FC = ({ size = 16, color }) => ( - + ); const VastBaseIcon: React.FC = ({ size = 16, color }) => ( - + ); const OpenGaussIcon: React.FC = ({ size = 16, color }) => ( - + ); const GaussDBIcon: React.FC = ({ size = 16, color }) => ( - + ); const GoldenDBIcon: React.FC = ({ size = 16, color }) => ( - + ); const HighGoIcon: React.FC = ({ size = 16, color }) => ( - + ); const IrisIcon: React.FC = ({ size = 16, color }) => ( - + ); const TDengineIcon: React.FC = ({ size = 16, color }) => ( - + ); const IoTDBIcon: React.FC = ({ size = 16, color }) => ( - + ); const RocketMQIcon: React.FC = ({ size = 16, color }) => ( - + ); const MQTTIcon: React.FC = ({ size = 16, color }) => ( - + ); const KafkaIcon: React.FC = ({ size = 16, color }) => ( - + ); const RabbitMQIcon: React.FC = ({ size = 16, color }) => ( - + ); const ChromaIcon: React.FC = ({ size = 16, color }) => ( - + ); const QdrantIcon: React.FC = ({ size = 16, color }) => ( - + ); const JVMIcon: React.FC = ({ size = 16, color }) => ( - + ); const ElasticsearchIcon: React.FC = ({ size = 16, color }) => ( - + ); /** Custom — 齿轮图标 */ @@ -239,13 +275,6 @@ const CustomIcon: React.FC = ({ size = 16, color }) => { // ─── 图标注册表 ───────────────────────────────────────────── -const DorisIconFallback: React.FC = ({ size = 16, color }) => ( - -); -const SphinxIconFallback: React.FC = ({ size = 16, color }) => ( - -); - const DB_ICON_MAP: Record> = { mysql: MySQLIcon, mariadb: MariaDBIcon, @@ -289,8 +318,8 @@ export const DB_ICON_TYPES: string[] = [ 'kingbase', 'dameng', 'vastbase', 'opengauss', 'gaussdb', 'goldendb', 'highgo', 'iris', 'tdengine', 'iotdb', 'rocketmq', 'mqtt', 'kafka', 'rabbitmq', 'chroma', 'qdrant', 'elasticsearch', 'custom', ]; -/** 该类型是否有品牌 SVG 文件 */ -export const hasBrandSvg = (type: string): boolean => BRAND_SVG_TYPES.has(type?.toLowerCase()); +/** 该类型是否有品牌图标资源 */ +export const hasBrandSvg = (type: string): boolean => BRAND_ASSET_TYPES.has(type?.toLowerCase()); /** 获取数据库图标 React 节点 */ export const getDbIcon = (type: string, color?: string, size?: number): React.ReactNode => {