diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a8b5ad..cc50f80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ > 所以不是每个版本号都有条目。条目格式 `## <版本> — <日期>`,新条目加在最上面。 > 工程口径的完整记录见 `PROGRESS.md` / git log。 +## 0.63.7 — 2026-08-11 + +- 已连接的外部系统现在可直接在凭据表单中重新连接并验证,不再被“该外部系统已连接”的重复创建提示拦住。 + ## 0.63.6 — 2026-08-11 - 修复外部系统配置弹框未按 OpenAPI、MCP 和认证方式切换配置项的问题;弹框滚动时不再带动后台页面。 diff --git a/PROGRESS.md b/PROGRESS.md index 90df3ff..d8a5b8f 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,7 +2,7 @@ > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。 -最后更新:2026-08-11(外部系统弹框动态字段与滚动隔离修复,bump 0.63.6) +最后更新:2026-08-11(外部系统已有连接直接重连修复,bump 0.63.7) --- @@ -23,6 +23,8 @@ ### 2026-08-11 +- **08-11 / 0.63.7 / 外部系统已有连接直接重连**:用户凭据表单按所选 definition 识别已有连接,自动切换为“重新连接并验证”并调用现有凭据更新接口,验证成功后保存新凭据和 active 状态,不再先按新连接提交后收到重复连接提示;卡片上的显式“更新凭据”入口保持不变。Web 无 DB 路由与静态资源共 35 项 unittest、JavaScript 语法及 diff 检查通过;无 schema、migration、HTTP API、依赖或运行方式变化,未连接生产 DB。 + - **08-11 / 0.63.6 / 外部系统弹框动态字段 + 滚动隔离修复**:修复表单 label 样式覆盖 HTML `hidden` 语义,OpenAPI/MCP connector、认证方式和接口执行模式切换后只显示适用配置项;弹框改为独立可收缩滚动区,并在打开期间锁定根页面滚动,滚动到边界不再带动后台页面。Node 前端 19 项、Web 公共逻辑 unittest 3 项、JavaScript 语法及 diff 检查通过;无 schema、migration、HTTP API、依赖或运行方式变化,未连接生产 DB。 - **08-11 / 0.63.5 / 外部系统配置弹框 + 动态字段**:管理后台外部系统定义由页面平铺表单改为新增/编辑弹框,按 OpenAPI/MCP connector 和认证方式只展示、提交当前适用字段;MCP URL 自动提供认证同源基址,新建时不再重复要求 Base URL,编辑存量定义继续保留既有基址,列表能力模式对 MCP 改为动态 `tools/list`。Web 无 DB 路由 23 项、JavaScript 语法、动态 DOM 引用及 diff 检查通过;当前运行时未发现可连接浏览器,真实点击冒烟待浏览器配置恢复后补验。无 schema、migration、HTTP API、依赖或运行方式变化,未连接生产 DB。 diff --git a/core/__init__.py b/core/__init__.py index 6015b4f..a8e43f0 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,3 +1,3 @@ # zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。 # 改版本只动这一行。 -__version__ = "0.63.6" +__version__ = "0.63.7" diff --git a/web/static/js/external_systems.js b/web/static/js/external_systems.js index 6cdff27..b4b5c54 100644 --- a/web/static/js/external_systems.js +++ b/web/static/js/external_systems.js @@ -22,6 +22,16 @@ function renderCredentialFields(fields = []) { `).join(""); } +function connectionForDefinition(definitionId) { + return Array.from(systemsById.values()) + .find(item => item.definition_id === definitionId); +} + +function submitButtonLabel() { + if (!editingId) return "连接并验证"; + return $("ext-definition").disabled ? "验证并更新" : "重新连接并验证"; +} + function resetForm() { editingId = ""; $("ext-form-title").textContent = "连接外部系统"; @@ -31,8 +41,18 @@ function resetForm() { $("ext-save").textContent = "连接并验证"; $("ext-form-cancel").hidden = true; const selected = selectedDefinition() || definitions[0]; - $("ext-name").value = selected ? selected.name : ""; - renderCredentialFields((selected || {}).credential_fields || []); + const connection = selected && connectionForDefinition(selected.definition_id); + if (connection) { + editingId = connection.external_system_id; + $("ext-form-title").textContent = `重新连接${connection.system_name || "外部系统"}`; + $("ext-name").value = connection.name; + $("ext-name").disabled = true; + $("ext-save").textContent = "重新连接并验证"; + renderCredentialFields(connection.credential_fields || []); + } else { + $("ext-name").value = selected ? selected.name : ""; + renderCredentialFields((selected || {}).credential_fields || []); + } } export function closeExternalSystemsModal() { @@ -106,10 +126,8 @@ $("external-modal").addEventListener("click", event => { }); $("ext-form-cancel").onclick = resetForm; $("ext-definition").onchange = () => { - if (editingId) return; - const selected = selectedDefinition(); - if (selected) $("ext-name").value = selected.name; - renderCredentialFields((selected || {}).credential_fields || []); + if ($("ext-definition").disabled) return; + resetForm(); }; $("ext-form").addEventListener("submit", async event => { @@ -132,7 +150,7 @@ $("ext-form").addEventListener("submit", async event => { try { if (editingId) { await api("PUT", `/v1/external-systems/${editingId}/credentials`, { credentials }); - message("外部系统凭据已更新", "success"); + message("外部系统已重新连接,凭据已更新", "success"); } else { await api("POST", "/v1/external-systems", { definition_id: definitionId, name, credentials }); message("外部系统已连接;下一轮对话即可使用", "success"); @@ -143,7 +161,7 @@ $("ext-form").addEventListener("submit", async event => { $("ext-err").textContent = error.message; } finally { button.disabled = !providerReady; - button.textContent = editingId ? "验证并更新" : "连接并验证"; + button.textContent = submitButtonLabel(); } });