import React from "react"; import { Alert, Button, Checkbox, Form, Input, Select, Space, Table, Tag, Typography, } from "antd"; import { ApiOutlined, ClusterOutlined, ThunderboltOutlined, } from "@ant-design/icons"; import type { MongoMemberInfo, SavedConnection } from "../types"; import { getStoredSecretPlaceholder, type ConnectionConfigSectionKey, } from "../utils/connectionModalPresentation"; import { noAutoCapInputProps } from "../utils/inputAutoCap"; const { Text } = Typography; type ChoiceCardOption = { value: string; label: string; description?: string; }; type RenderChoiceCards = (params: { fieldName: string; value: string; options: ChoiceCardOption[]; minWidth?: number; onSelect?: (value: string) => void; }) => React.ReactNode; type RenderConfigSectionCard = (params: { sectionKey: ConnectionConfigSectionKey; icon: React.ReactNode; children: React.ReactNode; badge?: React.ReactNode; }) => React.ReactNode; type RenderStoredSecretControls = (params: { fieldName: string; clearKey: "mongoReplicaPassword"; hasStoredSecret?: boolean; clearLabel: string; description: string; }) => React.ReactNode; interface ConnectionModalMongoSectionsProps { mongoTopology: string; mongoSrv: boolean; useSSH: boolean; darkMode: boolean; modalMutedTextStyle: React.CSSProperties; mongoReadPreference: string; mongoMembers: MongoMemberInfo[]; discoveringMembers: boolean; initialValues?: SavedConnection | null; renderChoiceCards: RenderChoiceCards; renderConfigSectionCard: RenderConfigSectionCard; renderStoredSecretControls: RenderStoredSecretControls; setChoiceFieldValue: (fieldName: string, value: string | boolean) => void; handleDiscoverMongoMembers: () => void; } const ConnectionModalMongoSections: React.FC = ({ mongoTopology, mongoSrv, useSSH, darkMode, modalMutedTextStyle, mongoReadPreference, mongoMembers, discoveringMembers, initialValues, renderChoiceCards, renderConfigSectionCard, renderStoredSecretControls, setChoiceFieldValue, handleDiscoverMongoMembers, }) => ( <> {renderConfigSectionCard({ sectionKey: "connectionMode", icon: , children: renderChoiceCards({ fieldName: "mongoTopology", value: String(mongoTopology), options: [ { value: "single", label: "单机模式", description: "只连接一个 MongoDB 节点。", }, { value: "replica", label: "副本集 / 多节点", description: "配置副本集名称和多个候选节点。", }, ], }), })} {renderConfigSectionCard({ sectionKey: "mongoDiscovery", icon: , children: ( <>
{[ { value: false, label: "标准地址", description: "使用 host:port 直连或副本集节点列表。", }, { value: true, label: "SRV 地址", description: "使用 mongodb+srv,由 DNS 发现目标节点。", }, ].map((option) => { const active = mongoSrv === option.value; return ( ); })}
{mongoSrv && useSSH && ( )} ), })} {mongoTopology === "replica" && renderConfigSectionCard({ sectionKey: "replica", icon: , children: ( <> {renderStoredSecretControls({ fieldName: "mongoReplicaPassword", clearKey: "mongoReplicaPassword", hasStoredSecret: initialValues?.hasMongoReplicaPassword, clearLabel: "清除已保存副本集密码", description: "当前已保存副本集密码。留空表示继续沿用,输入新值表示替换。", })} {mongoMembers.length > 0 && ( record.host} pagination={false} dataSource={mongoMembers} style={{ marginBottom: 12 }} columns={[ { title: "Host", dataIndex: "host", width: "48%" }, { title: "角色", dataIndex: "role", width: "32%", render: (value: string, record: MongoMemberInfo) => ( {value || "UNKNOWN"} ), }, { title: "健康", dataIndex: "healthy", width: "20%", render: (value: boolean) => ( {value ? "正常" : "异常"} ), }, ]} /> )} ), })} {renderConfigSectionCard({ sectionKey: "mongoPolicy", icon: , children: (
读偏好 (readPreference) {renderChoiceCards({ fieldName: "mongoReadPreference", value: String(mongoReadPreference), minWidth: 130, options: [ { value: "primary", label: "primary", description: "只读主节点。", }, { value: "primaryPreferred", label: "primaryPreferred", description: "主节点优先。", }, { value: "secondary", label: "secondary", description: "只读从节点。", }, { value: "secondaryPreferred", label: "secondaryPreferred", description: "从节点优先。", }, { value: "nearest", label: "nearest", description: "选择最近节点。", }, ], })}
), })} ); export default ConnectionModalMongoSections;