import React from 'react'; import { Button, Input, Popconfirm, Radio, Space, Tag } from 'antd'; import type { RadioChangeEvent } from 'antd'; import { DeleteOutlined, PlusOutlined, ReloadOutlined, SearchOutlined } from '@ant-design/icons'; import type { SavedConnection } from '../types'; import { t, type I18nParams } from '../i18n'; import { useOptionalI18n } from '../i18n/provider'; import { noAutoCapInputProps } from '../utils/inputAutoCap'; import type { RedisSearchMode } from '../utils/redisSearchPattern'; const { Search } = Input; const normalizeText = (value: unknown): string => String(value || '').trim(); const normalizeRedisTopology = (connection?: SavedConnection): 'single' | 'cluster' | 'sentinel' => { const topology = normalizeText(connection?.config?.topology).toLowerCase(); if (topology === 'sentinel') return 'sentinel'; if (topology === 'cluster') return 'cluster'; const extraHosts = Array.isArray(connection?.config?.hosts) ? connection.config.hosts.filter(Boolean) : []; return extraHosts.length > 0 ? 'cluster' : 'single'; }; const buildRedisSeedAddresses = (connection?: SavedConnection): string[] => { if (!connection) return []; const config = connection.config || {}; const port = Number.isFinite(Number(config.port)) ? Number(config.port) : 6379; const primary = normalizeText(config.host) ? `${normalizeText(config.host)}:${port}` : ''; const extraHosts = Array.isArray(config.hosts) ? config.hosts.map((host) => normalizeText(host)).filter(Boolean) : []; return [primary, ...extraHosts].filter(Boolean); }; const getRedisTopologyLabel = ( topology: 'single' | 'cluster' | 'sentinel', tr: (key: string, params?: I18nParams) => string, ): string => { if (topology === 'cluster') return tr('redis_viewer.topology.cluster'); if (topology === 'sentinel') return tr('redis_viewer.topology.sentinel'); return tr('redis_viewer.topology.single'); }; type RedisViewerKeyToolbarProps = { isV2Ui: boolean; redisDB: number; connection?: SavedConnection; keyCount: number; selectedKeyCount: number; searchMode: RedisSearchMode; searchInput: string; mutedPillTagStyle: React.CSSProperties; actionButtonStyle: React.CSSProperties; primaryActionButtonStyle: React.CSSProperties; dangerActionButtonStyle: React.CSSProperties; textMutedColor: string; textPrimaryColor: string; onSearchModeChange: (event: RadioChangeEvent) => void; onSearchInputChange: (event: React.ChangeEvent) => void; onSearch: (value: string) => void; onRefresh: () => void; onCreateKey: () => void; onSelectAllLoadedKeys: () => void; onClearAllSelectedKeys: () => void; onDeleteSelectedKeys: () => void; }; const RedisViewerKeyToolbar: React.FC = ({ isV2Ui, redisDB, connection, keyCount, selectedKeyCount, searchMode, searchInput, mutedPillTagStyle, actionButtonStyle, primaryActionButtonStyle, dangerActionButtonStyle, textMutedColor, textPrimaryColor, onSearchModeChange, onSearchInputChange, onSearch, onRefresh, onCreateKey, onSelectAllLoadedKeys, onClearAllSelectedKeys, onDeleteSelectedKeys, }) => { const i18n = useOptionalI18n(); const i18nLanguage = i18n?.language; const tr = (key: string, params?: I18nParams) => t(key, params, i18nLanguage); const topology = normalizeRedisTopology(connection); const seedAddresses = buildRedisSeedAddresses(connection); const sentinelMaster = topology === 'sentinel' ? normalizeText(connection?.config?.redisSentinelMaster) : ''; return (
{tr('redis_viewer.title.key_explorer')}
db{redisDB}
{getRedisTopologyLabel(topology, tr)} {topology !== 'single' && ( {tr('redis_viewer.label.node_count', { count: seedAddresses.length || 1 })} )} {sentinelMaster && ( master: {sentinelMaster} )}
{tr('redis_viewer.label.keys_count', { count: keyCount })}
{tr('redis_viewer.search.fuzzy')} {tr('redis_viewer.search.exact')} } />
); }; export default RedisViewerKeyToolbar;