From 69d9f410856319681a0665117321e9560bc903ee Mon Sep 17 00:00:00 2001 From: Syngnat Date: Thu, 2 Jul 2026 14:12:47 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(connection):=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=94=9F=E4=BA=A7=E4=BF=9D=E6=8A=A4=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=8A=98=E5=8F=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为连接配置分区卡片增加可折叠渲染能力 - 生产连接保护默认收起,仅保留标题说明和当前策略标签 - 补充中英文折叠态与展开态回归测试 --- .../components/ConnectionModal.i18n.test.tsx | 21 ++++++- frontend/src/components/ConnectionModal.tsx | 60 ++++++++++++++++++- .../connectionModal/ConnectionModalStep2.tsx | 13 +++- 3 files changed, 89 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/ConnectionModal.i18n.test.tsx b/frontend/src/components/ConnectionModal.i18n.test.tsx index 61104cff..5d90f90e 100644 --- a/frontend/src/components/ConnectionModal.i18n.test.tsx +++ b/frontend/src/components/ConnectionModal.i18n.test.tsx @@ -162,6 +162,8 @@ vi.mock("@ant-design/icons", () => { GatewayOutlined: Icon, SafetyCertificateOutlined: Icon, ThunderboltOutlined: Icon, + DownOutlined: Icon, + RightOutlined: Icon, }; }); @@ -526,7 +528,24 @@ describe("ConnectionModal i18n", () => { findClickableCard(renderer!, sourceLabel).props.onClick(); }); - const pageText = textContent(renderer!.toJSON()); + let pageText = textContent(renderer!.toJSON()); + expect(pageText).toContain(expectations[0]); + expect(pageText).toContain( + language === "zh-CN" ? "未限制" : "No restrictions", + ); + expect(pageText).not.toContain(expectations[1]); + expect(pageText).not.toContain(expectations[2]); + + const protectionToggle = renderer!.root.findAll( + (node) => node.props?.["data-connection-config-section-toggle"] === "readOnly", + )[0]; + expect(protectionToggle.props["aria-expanded"]).toBe(false); + + await act(async () => { + protectionToggle.props.onClick({ stopPropagation: vi.fn() }); + }); + + pageText = textContent(renderer!.toJSON()); expectations.forEach((expected) => { expect(pageText).toContain(expected); }); diff --git a/frontend/src/components/ConnectionModal.tsx b/frontend/src/components/ConnectionModal.tsx index 6503f4f3..33dcb6ed 100644 --- a/frontend/src/components/ConnectionModal.tsx +++ b/frontend/src/components/ConnectionModal.tsx @@ -34,6 +34,8 @@ import { GatewayOutlined, SafetyCertificateOutlined, ThunderboltOutlined, + DownOutlined, + RightOutlined, } from "@ant-design/icons"; import { getDbIcon, @@ -693,14 +695,21 @@ const ConnectionModal: React.FC<{ title: string, description: string, badge?: React.ReactNode, + options?: { + cursor?: React.CSSProperties["cursor"]; + marginBottom?: number; + onClick?: () => void; + }, ) => (
@@ -758,20 +767,65 @@ const ConnectionModal: React.FC<{ icon, children, badge, + collapsible, + expanded = true, + onToggle, }: { sectionKey: ConnectionConfigSectionKey; icon: React.ReactNode; children: React.ReactNode; badge?: React.ReactNode; + collapsible?: boolean; + expanded?: boolean; + onToggle?: () => void; }) => { const copy = getConnectionConfigSectionCopy(sectionKey); + const showChildren = !collapsible || expanded; + const resolvedBadge = collapsible ? ( + + {badge} + + + ) : badge; return (
- {renderJvmSectionHeader(icon, copy.title, copy.description, badge)} - {children} + {renderJvmSectionHeader( + icon, + copy.title, + copy.description, + resolvedBadge, + collapsible + ? { + cursor: "pointer", + marginBottom: showChildren ? 14 : 0, + onClick: onToggle, + } + : undefined, + )} + {showChildren ? children : null}
); }; diff --git a/frontend/src/components/connectionModal/ConnectionModalStep2.tsx b/frontend/src/components/connectionModal/ConnectionModalStep2.tsx index 33b56ff2..171c2354 100644 --- a/frontend/src/components/connectionModal/ConnectionModalStep2.tsx +++ b/frontend/src/components/connectionModal/ConnectionModalStep2.tsx @@ -194,7 +194,14 @@ const ConnectionModalStep2: React.FC = (props) => { useSSL, } = props; -const renderStep2 = () => { + const [readOnlyProtectionExpanded, setReadOnlyProtectionExpanded] = + React.useState(false); + + React.useEffect(() => { + setReadOnlyProtectionExpanded(false); + }, [dbType]); + + const renderStep2 = () => { const showConnectionReadOnlyField = supportsConnectionReadOnlyMode({ type: dbType, driver: form.getFieldValue("driver"), @@ -1364,6 +1371,10 @@ const renderStep2 = () => { renderConfigSectionCard({ sectionKey: "readOnly", icon: , + collapsible: true, + expanded: readOnlyProtectionExpanded, + onToggle: () => + setReadOnlyProtectionExpanded((expanded) => !expanded), badge: (