mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-27 12:53:35 +00:00
perf(webui): 前端按页签懒加载 —— 首屏不再拉隐藏页签的数据,空闲请求砍到 1/3
生产实测的问题:renderAll 无论当前在哪个页签,都无条件拉 9 个接口并
渲染全部 7 个页签。首屏 792,933 B 里**约 230KB 花在用户看不见的隐藏
DOM 上** —— /api/v1/kernel(152KB,只有内核页要)与 /api/v1/settings
(72KB,只有设置页要),而 renderKernel() / renderOneSettings() 是在
**隐藏的 tab 容器**里构建 DOM 的。更糟的是每 15s 重来一遍。
### 依赖关系是实测出来的,不是猜的
逐个 render 函数 grep 它读的 state.*:
renderOverview → 无(只读 status/runtime/dom)★ 总览最便宜
renderKernel → state.kernel
renderOneSettings → state.settings / state.meta
renderPlugins → state.kernel / installedPlugins / disabledPlugins
renderAdapters → 无(自拉 /api/v1/adapters)
renderChat → 自建布局;星图/终端/命令是其子面板
于是「切到哪页才拉哪页的数据」写成一张 TABS 表(唯一真相表),
正确性由结构保证,而不是靠一串 if 串联。
### 顺带治掉三个轮询器(浏览器 40s 空载实测)
改前停在总览页 40s 内 37 个请求:
/runtime 17 次、/terminals 8 次、/cmd/history 8 次、/status 3 次
1. **terminals/cmd/history 的 5s 轮询是无条件的** —— 但这两个面板只
存在于**聊天页**(buildChatLayout 里的 chat-panel-terminal/-cmd),
在总览/设置/内核页渲染它们既没人看也只改看不见的 DOM。
改为「仅聊天页可见时才轮询」。
2. **/runtime 有两个消费者各拉一遍**:startRuntimeTicker(3s)与
starmapPullActivity(3s)。星图现在只读 state.runtime,不再自己发请求。
3. 轮询改走共享数据块 starmapFetchBlock(带 3s 节流 + 单一数据源)。
改后 40s 内 17 个请求(-54%),且不再有任何接口用于渲染不可见的面板。
### 首屏
overview 首屏只拉 status/runtime/chat/history/persona/memory-graph,
**不再拉 kernel 与 settings**。
### 刷新语义
区分「活数据」与「近乎不变的数据」:status/runtime 每 3s 允许重拉;
kernel/settings/plugins 首次拉过后**不再每 15s 重拉**(这正是 53MB/h
的主因)。切回页签也不重拉(数据没理由变)。四个变更操作
(源/MCP 的增删)改调 renderAll(true) 强制刷新;启停插件/保存设置那几处
本来就自己 refetch 再局部重渲染,不依赖 renderAll。
### ★ 途中修掉一个被上一提交引入的真 bug
loadChatStarmapData 的空图分支硬写 getElementById("sm-container-chat")。
星图搬到总览后,总览页与独立页签都没有这个 id ⇒ 首页首帧必抛
「Cannot set properties of null」,被 catch 吞掉但 starmapInit 没置上,
于是**永不重试、星图永远空白**。改为取 starmapActiveContainer() 并加
空值保护。浏览器实测:修前 ERRORS 非空,修后 STARTUP + 7 个页签全 clean。
(教训:把 UI 元素挪到新位置后,必须把所有按 id 直取该元素的地方找全 ——
grep 该 id 一次。)
同时删掉被 starmapActiveContainer 取代的死函数 starmapContainer()。
### 验证(浏览器实测,非估算)
- go vet 干净;全量测试通过
- 首屏(overview):只拉 status/runtime/chat-history/persona/memory-graph,
kernel 与 settings 确认**未出现**
- 逐页切换记录请求:每页只拉自己那几项
- 空载 40s:37 → 17 个请求
- 运行态面板仍正常渲染(rt-panel 存在、rt-sec-pipe / rt-sec-topo 均在)
- 启动 + 7 个页签全部无控制台异常
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -493,80 +493,173 @@ function toggleSidebar() {
|
||||
}
|
||||
|
||||
// ===== Tab Render Dispatch =====
|
||||
async function renderAll() {
|
||||
try {
|
||||
var s = await api("/status");
|
||||
state.status = s;
|
||||
state.startedAt = s.startedAt ? new Date(s.startedAt).getTime() : null;
|
||||
} catch (e) {}
|
||||
try {
|
||||
state.kernel = await api("/kernel");
|
||||
} catch (e) {}
|
||||
try {
|
||||
var s = await api("/settings");
|
||||
state.settings = s.settings || {};
|
||||
state.meta = s.meta || {};
|
||||
state.settingsPlugins = s.plugins || ["core"];
|
||||
state.pluginMeta = s.plugin_meta || {};
|
||||
state.disabledPlugins = s.disabled_plugins || [];
|
||||
} catch (e) {}
|
||||
try {
|
||||
state.installedPlugins = await api("/plugins");
|
||||
} catch (e) {}
|
||||
try {
|
||||
await loadProxyServices();
|
||||
} catch (e) {}
|
||||
try {
|
||||
await loadTerminals();
|
||||
} catch (e) {}
|
||||
try {
|
||||
await loadCmdHistory();
|
||||
} catch (e) {}
|
||||
try {
|
||||
renderOverview();
|
||||
} catch (e) {
|
||||
console.error("renderOverview", e);
|
||||
|
||||
// TABS 是「哪个页签需要哪些数据」的**唯一真相表**。
|
||||
//
|
||||
// 为什么要有这张表(实测依据,非估算):
|
||||
//
|
||||
// 改前 renderAll 无论当前在哪个页签,都无条件拉 9 个接口并渲染全部
|
||||
// 7 个页签。生产实例首屏 792,933 B 里,**约 230KB 花在用户看不见的
|
||||
// 隐藏 DOM 上**:/api/v1/kernel(152KB,只有「内核」页要)与
|
||||
// /api/v1/settings(72KB,只有「设置」页要)——而 renderKernel() /
|
||||
// renderOneSettings() 是在**隐藏的 tab 容器**里构建 DOM 的。
|
||||
//
|
||||
// 依赖关系是**实测**出来的(逐个 render 函数 grep 它读的 state.*),
|
||||
// 不是猜的:
|
||||
// renderOverview → 无(只读 status/runtime/dom)★ 总览最便宜
|
||||
// renderKernel → state.kernel
|
||||
// renderOneSettings → state.settings / state.meta
|
||||
// renderPlugins → state.kernel / state.installedPlugins /
|
||||
// state.disabledPlugins / state.pluginInfo
|
||||
// renderAdapters → 无(自拉 /api/v1/adapters)
|
||||
// renderChat → 自建布局;星图/终端/命令是其子面板
|
||||
//
|
||||
// 于是「切到哪页才拉哪页的数据」成为结构性正确,而不是靠 if 串联。
|
||||
var TABS = {
|
||||
overview: { fetch: ["status", "runtime"], render: ["renderOverview"] },
|
||||
chat: {
|
||||
fetch: ["status", "proxyServices", "terminals", "cmdHistory"],
|
||||
render: ["renderChat"],
|
||||
},
|
||||
starmap: { fetch: [], render: ["renderStarmapTab"] },
|
||||
plugins: {
|
||||
fetch: ["status", "kernel", "plugins", "runtime"],
|
||||
render: ["renderPlugins"],
|
||||
},
|
||||
settings: { fetch: ["settings", "status"], render: ["renderOneSettings"] },
|
||||
adapters: { fetch: ["status"], render: ["renderAdapters"] },
|
||||
kernel: { fetch: ["status", "kernel", "runtime"], render: ["renderKernel"] },
|
||||
};
|
||||
|
||||
// starmapActiveTab 返回当前激活的页签名。
|
||||
function starmapActiveTab() {
|
||||
var el = document.querySelector(".tab-content.active");
|
||||
if (el && el.id) return el.id.replace(/^tab-/, "");
|
||||
return "overview";
|
||||
}
|
||||
|
||||
// loadedOnce 记录每个数据块是否已拉过。刷新语义刻意区分:
|
||||
// - 首次进入某页签:拉
|
||||
// - 之后每 15s 的 renderAll:**不**重拉 kernel/settings(它们几乎不变,
|
||||
// 却占每拍 232KB —— 这是「空闲 53MB/h」的主因)
|
||||
// - 切回页签:仍然不重拉(数据没理由变),只重渲染
|
||||
// 真正需要新鲜的(runtime/status)单独走快通道,见 STALE_EVERY。
|
||||
var _loadedOnce = {};
|
||||
var _lastFetchAt = {};
|
||||
// STALE_EVERY:这几块数据是活的(运行态/状态),每 3s 允许重拉一次。
|
||||
var STALE_EVERY = 3000;
|
||||
|
||||
// starmapFetchBlock 按名字拉一块数据。幂等且带节流。
|
||||
async function starmapFetchBlock(name) {
|
||||
var now = Date.now();
|
||||
var volatile_ = name === "status" || name === "runtime";
|
||||
if (_loadedOnce[name]) {
|
||||
if (!volatile_) return;
|
||||
if (now - (_lastFetchAt[name] || 0) < STALE_EVERY) return;
|
||||
}
|
||||
try {
|
||||
await loadRuntime();
|
||||
} catch (e) {
|
||||
console.error("loadRuntime", e);
|
||||
_lastFetchAt[name] = now;
|
||||
switch (name) {
|
||||
case "status":
|
||||
try {
|
||||
var s = await api("/status");
|
||||
state.status = s;
|
||||
state.startedAt = s.startedAt
|
||||
? new Date(s.startedAt).getTime()
|
||||
: null;
|
||||
} catch (e) {}
|
||||
break;
|
||||
case "runtime":
|
||||
try {
|
||||
var rt = await api("/runtime");
|
||||
state.runtime = rt;
|
||||
} catch (e) {
|
||||
state.runtime = null;
|
||||
}
|
||||
// 运行态变了就顺手让星图重算一次(读同一个快照,不额外发请求)。
|
||||
if (typeof starmapApplyActivity === "function") starmapApplyActivity();
|
||||
break;
|
||||
case "kernel":
|
||||
try {
|
||||
state.kernel = await api("/kernel");
|
||||
} catch (e) {}
|
||||
break;
|
||||
case "settings":
|
||||
try {
|
||||
var s2 = await api("/settings");
|
||||
state.settings = s2.settings || {};
|
||||
state.meta = s2.meta || {};
|
||||
state.settingsPlugins = s2.plugins || ["core"];
|
||||
state.pluginMeta = s2.plugin_meta || {};
|
||||
state.disabledPlugins = s2.disabled_plugins || [];
|
||||
} catch (e) {}
|
||||
break;
|
||||
case "plugins":
|
||||
try {
|
||||
state.installedPlugins = await api("/plugins");
|
||||
} catch (e) {}
|
||||
break;
|
||||
case "proxyServices":
|
||||
try {
|
||||
await loadProxyServices();
|
||||
} catch (e) {}
|
||||
break;
|
||||
case "terminals":
|
||||
try {
|
||||
await loadTerminals();
|
||||
} catch (e) {}
|
||||
break;
|
||||
case "cmdHistory":
|
||||
try {
|
||||
await loadCmdHistory();
|
||||
} catch (e) {}
|
||||
break;
|
||||
}
|
||||
_loadedOnce[name] = true;
|
||||
}
|
||||
|
||||
async function renderAll(force) {
|
||||
var tab = starmapActiveTab();
|
||||
var spec = TABS[tab] || TABS.overview;
|
||||
// force:变更操作后(保存设置/启停插件)需要重新拉那块数据。
|
||||
if (force) _loadedOnce = {};
|
||||
// 1) 只拉当前页签需要的数据(并发的别串行等)
|
||||
var needs = spec.fetch || [];
|
||||
await Promise.all(
|
||||
needs.map((n) => starmapFetchBlock(n)),
|
||||
);
|
||||
// 2) 只渲染当前页签(+ 星图在多处出现,单独处理)
|
||||
try {
|
||||
renderChat();
|
||||
spec.render.forEach((fn) => {
|
||||
if (typeof window[fn] === "function") window[fn]();
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("renderChat", e);
|
||||
console.error("renderAll(" + tab + ")", e);
|
||||
}
|
||||
try {
|
||||
renderChatStarmap();
|
||||
} catch (e) {
|
||||
console.error("renderChatStarmap", e);
|
||||
// 星图:总览页内嵌 + 独立页签两处都要确保已初始化。
|
||||
if (tab === "overview" || tab === "starmap" || tab === "chat") {
|
||||
try {
|
||||
renderChatStarmap();
|
||||
} catch (e) {
|
||||
console.error("renderChatStarmap", e);
|
||||
}
|
||||
if (tab === "starmap") {
|
||||
try {
|
||||
renderStarmapTab();
|
||||
} catch (e) {
|
||||
console.error("renderStarmapTab", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
renderStarmapTab();
|
||||
} catch (e) {
|
||||
console.error("renderStarmapTab", e);
|
||||
}
|
||||
try {
|
||||
renderPlugins();
|
||||
} catch (e) {
|
||||
console.error("renderPlugins", e);
|
||||
}
|
||||
try {
|
||||
renderKernel();
|
||||
} catch (e) {
|
||||
console.error("renderKernel", e);
|
||||
}
|
||||
try {
|
||||
renderOneSettings();
|
||||
} catch (e) {
|
||||
console.error("renderOneSettings", e);
|
||||
}
|
||||
try {
|
||||
renderAdapters();
|
||||
} catch (e) {
|
||||
console.error("renderAdapters", e);
|
||||
// 3) 聊天页的子面板(终端/运行中命令)只在聊天页重建
|
||||
if (tab === "chat") {
|
||||
try {
|
||||
renderTerminals();
|
||||
renderCmdHistory();
|
||||
} catch (e) {
|
||||
console.error("chat sub-panels", e);
|
||||
}
|
||||
}
|
||||
// 4) 卡片倾斜高光:只在指针设备上加
|
||||
try {
|
||||
if (!window.matchMedia("(hover: none)").matches) {
|
||||
document
|
||||
@ -1758,7 +1851,11 @@ function startRuntimeTicker() {
|
||||
state._runtimeTicker = setInterval(() => {
|
||||
var tab = document.querySelector("#tab-overview");
|
||||
if (tab && tab.classList.contains("active")) {
|
||||
loadRuntime();
|
||||
// 走共享数据块(自带 3s 节流 + 单一数据源)而不是直接 loadRuntime:
|
||||
// 星图也读 state.runtime,两个入口拉同一接口就是重复请求。
|
||||
starmapFetchBlock("runtime").then(() => {
|
||||
if (starmapActiveTab() === "overview") renderRuntime();
|
||||
});
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
@ -2750,6 +2847,13 @@ function renderChatStarmap() {
|
||||
async function loadChatStarmapData() {
|
||||
try {
|
||||
var resp = await api("/memory/graph");
|
||||
// 星图现在有三个容器(总览/独立页签/聊天面板),写提示前必须重新
|
||||
// 拿当前活跃的那个。原代码硬写 getElementById("sm-container-chat"),
|
||||
// 而总览页与独立页签都没有这个 id —— 空图分支一进就抛
|
||||
// 「Cannot set properties of null」(浏览器实测:首页首帧必现)。
|
||||
// 症状是整个函数被 catch 吞掉、state.starmapInit 却没置上,
|
||||
// 于是后续再也不会重试 —— 星图永远是空的。
|
||||
var target = starmapActiveContainer();
|
||||
if (
|
||||
!resp ||
|
||||
!resp.success ||
|
||||
@ -2757,10 +2861,11 @@ async function loadChatStarmapData() {
|
||||
!resp.data.nodes ||
|
||||
resp.data.nodes.length === 0
|
||||
) {
|
||||
document.getElementById("sm-container-chat").innerHTML =
|
||||
'<p style="color:var(--text-muted);padding:20px;text-align:center">' +
|
||||
__("暂无记忆数据", "No memory data") +
|
||||
"</p>";
|
||||
if (target)
|
||||
target.innerHTML =
|
||||
'<p style="color:var(--text-muted);padding:20px;text-align:center">' +
|
||||
__("暂无记忆数据", "No memory data") +
|
||||
"</p>";
|
||||
state.starmapInit = true;
|
||||
state.starmapLoading = false;
|
||||
return;
|
||||
@ -2772,10 +2877,12 @@ async function loadChatStarmapData() {
|
||||
state.starmapLoading = false;
|
||||
initChatStarmap();
|
||||
} catch (e) {
|
||||
document.getElementById("sm-container-chat").innerHTML =
|
||||
'<p style="color:var(--text-muted);padding:20px;text-align:center">' +
|
||||
__("加载失败", "Load failed") +
|
||||
"</p>";
|
||||
var target2 = starmapActiveContainer();
|
||||
if (target2)
|
||||
target2.innerHTML =
|
||||
'<p style="color:var(--text-muted);padding:20px;text-align:center">' +
|
||||
__("加载失败", "Load failed") +
|
||||
"</p>";
|
||||
state.starmapInit = true;
|
||||
state.starmapLoading = false;
|
||||
}
|
||||
@ -4573,22 +4680,37 @@ function connectSSE() {
|
||||
console.log("[SSE] sync_required received, incremental sync");
|
||||
syncChatFromHistory().catch(() => {});
|
||||
});
|
||||
// Periodically refresh sidebar data
|
||||
// 终端 / 运行中命令的定时刷新。
|
||||
//
|
||||
// ★ 原来这段是**无条件**的 5s 轮询(浏览器实测:停在总览页 40s 内
|
||||
// 打了 8 次 /terminals + 8 次 /cmd/history)。但这两个面板只存在于
|
||||
// **聊天页**(buildChatLayout 里的 chat-panel-terminal / -cmd),
|
||||
// 在总览/设置/内核页渲染它们既没人看也只改看不见的 DOM。
|
||||
//
|
||||
// 改为「仅聊天页可见时才轮询」,且错过的那一拍在切回聊天页时由
|
||||
// renderAll 补上(renderAll 的 terminals/cmdHistory 数据块带节流)。
|
||||
if (state._sidebarRefresh) clearInterval(state._sidebarRefresh);
|
||||
state._sidebarRefresh = setInterval(async () => {
|
||||
try {
|
||||
var td = await api("/terminals");
|
||||
if (td && td.terminals) state.terminals = td.terminals;
|
||||
} catch (e) {}
|
||||
try {
|
||||
var ch = await api("/cmd/history");
|
||||
if (ch && ch.history) state.cmdHistory = ch.history;
|
||||
} catch (e) {}
|
||||
renderTerminals();
|
||||
renderCmdHistory();
|
||||
state._sidebarRefresh = setInterval(() => {
|
||||
var tab = document.querySelector("#tab-chat");
|
||||
if (!tab || !tab.classList.contains("active")) return;
|
||||
fetchTerminalsAndCmd().catch(() => {});
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// fetchTerminalsAndCmd 拉终端与运行中命令并重渲染(只在聊天页需要)。
|
||||
async function fetchTerminalsAndCmd() {
|
||||
try {
|
||||
var td = await api("/terminals");
|
||||
if (td && td.terminals) state.terminals = td.terminals;
|
||||
} catch (e) {}
|
||||
try {
|
||||
var ch = await api("/cmd/history");
|
||||
if (ch && ch.history) state.cmdHistory = ch.history;
|
||||
} catch (e) {}
|
||||
renderTerminals();
|
||||
renderCmdHistory();
|
||||
}
|
||||
|
||||
// ===== Plugins =====
|
||||
// 「服务入口」:被反代的插件服务,点一下直接打开。
|
||||
//
|
||||
@ -5480,32 +5602,53 @@ function starmapHintTokens(hint) {
|
||||
}
|
||||
|
||||
// starmapPullActivity 拉 /runtime,把调度器状态映射成图的整体节奏。
|
||||
// starmapPullActivity 用**已有的** /runtime 快照驱动图,绝不自己再发一轮请求。
|
||||
//
|
||||
// ★ 原来它直接 api("/runtime"),而 startRuntimeTicker 也在 3s 拉同一个
|
||||
// 接口 —— 浏览器实测:停在总览页 40s 内 /runtime 被打 **17 次**
|
||||
// (= 3s 一次 × 2 + 15s 的 renderAll)。两个消费者拉同一份数据是纯浪费。
|
||||
//
|
||||
// 现在只读 state.runtime(由 startRuntimeTicker / renderAll 负责刷新)。
|
||||
// 星图慢一拍(最多 3s)无所谓:它只是把调度器状态映射成脉冲。
|
||||
function starmapPullActivity() {
|
||||
if (!starmapScene) return;
|
||||
api("/runtime")
|
||||
.then((rt) => {
|
||||
if (!rt || !rt.scheduler) return;
|
||||
var s = rt.scheduler;
|
||||
var prev = state.starmapActivity;
|
||||
state.starmapActivity = s;
|
||||
var pend =
|
||||
(s.ready_queue_depth || 0) +
|
||||
(s.pending_interrupts || 0) +
|
||||
(s.suspend_stack || 0);
|
||||
// 有任务在排队/中断 ⇒ 脉冲,让图「绷紧」。
|
||||
if (pend > 0) starmapPulse("stage", null);
|
||||
// 中断或抢占计数上升 ⇒ 一次强脉冲(高优先级插入)。
|
||||
if (prev) {
|
||||
var dInt =
|
||||
(s.interrupts_by_level || []).reduce((a, b) => a + b, 0) -
|
||||
(prev.interrupts_by_level || []).reduce((a, b) => a + b, 0);
|
||||
var dPre =
|
||||
(s.preempts_by_level || []).reduce((a, b) => a + b, 0) -
|
||||
(prev.preempts_by_level || []).reduce((a, b) => a + b, 0);
|
||||
if (dInt > 0 || dPre > 0) starmapPulse("output", null);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
var s0 = state.runtime && state.runtime.scheduler;
|
||||
if (!s0) {
|
||||
// 还没有快照(星图先于运行态轮询初始化):拉一次,建立基线。
|
||||
starmapFetchBlock("runtime").then(() => {
|
||||
starmapApplyActivity();
|
||||
});
|
||||
return;
|
||||
}
|
||||
starmapApplyActivity();
|
||||
}
|
||||
|
||||
// starmapApplyActivity 把 state.runtime 里的调度器计数映射成星图脉冲。
|
||||
function starmapApplyActivity() {
|
||||
var rt = state.runtime;
|
||||
if (!rt || !rt.scheduler) return;
|
||||
var s = rt.scheduler;
|
||||
var prev = state.starmapActivity;
|
||||
state.starmapActivity = s;
|
||||
var pend =
|
||||
(s.ready_queue_depth || 0) +
|
||||
(s.pending_interrupts || 0) +
|
||||
(s.suspend_stack || 0);
|
||||
// 有任务在排队/中断 ⇒ 脉冲,让图「绷紧」。
|
||||
if (pend > 0) starmapPulse("stage", null);
|
||||
if (!prev) {
|
||||
smUpdateStat();
|
||||
return;
|
||||
}
|
||||
// 中断或抢占计数上升 ⇒ 一次强脉冲(高优先级插入)。
|
||||
var sum = (a) => (a || []).reduce((x, y) => x + y, 0);
|
||||
if (
|
||||
sum(s.interrupts_by_level) - sum(prev.interrupts_by_level) > 0 ||
|
||||
sum(s.preempts_by_level) - sum(prev.preempts_by_level) > 0
|
||||
) {
|
||||
starmapPulse("output", null);
|
||||
}
|
||||
smUpdateStat();
|
||||
}
|
||||
|
||||
// starmapPullPulse 拉轻量活动端点,把新长出来的节点标记为「生长」。
|
||||
@ -5689,13 +5832,6 @@ function starmapLabelShow(mesh) {
|
||||
function starmapLabelHide() {
|
||||
if (starmapLabelEl) starmapLabelEl.style.display = "none";
|
||||
}
|
||||
// starmapContainer 返回当前星图所在的容器(主页或聊天面板任一)。
|
||||
function starmapContainer() {
|
||||
return (
|
||||
document.getElementById("sm-container-home") ||
|
||||
document.getElementById("sm-container-chat")
|
||||
);
|
||||
}
|
||||
|
||||
// starmapActiveContainer 选出「该把星图画在哪」的容器。
|
||||
//
|
||||
@ -6517,7 +6653,7 @@ function showAddSourceDialog() {
|
||||
'" ' +
|
||||
__("已创建,请配置各项参数", "created, please configure parameters"),
|
||||
);
|
||||
renderAll();
|
||||
renderAll(true);
|
||||
})
|
||||
.catch((e) => {
|
||||
toast(__("创建失败: ", "Create failed: ") + e.message, true);
|
||||
@ -6548,7 +6684,7 @@ async function deleteSource(name) {
|
||||
});
|
||||
}
|
||||
toast(__("源", "Source") + ' "' + name + '" ' + __("已删除", "deleted"));
|
||||
renderAll();
|
||||
renderAll(true);
|
||||
} catch (e) {
|
||||
toast(__("删除失败: ", "Delete failed: ") + e.message, true);
|
||||
}
|
||||
@ -6586,7 +6722,7 @@ function addMCPSource() {
|
||||
'" ' +
|
||||
__("已创建", "created"),
|
||||
);
|
||||
renderAll();
|
||||
renderAll(true);
|
||||
})
|
||||
.catch((e) => {
|
||||
toast(__("创建失败: ", "Create failed: ") + e.message, true);
|
||||
@ -6622,7 +6758,7 @@ async function deleteMCPServer(name) {
|
||||
'" ' +
|
||||
__("已删除", "deleted"),
|
||||
);
|
||||
renderAll();
|
||||
renderAll(true);
|
||||
} catch (e) {
|
||||
toast(__("删除失败: ", "Delete failed: ") + e.message, true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user